Skip to content

Guides

Errors, retries, and idempotency

The LyricWinter API response envelope, error codes, request IDs, retry rules, idempotency keys, and client mutation IDs for safe retries of paid operations.

BetaUpdated

Every LyricWinter API response uses a consistent JSON envelope, and every error carries a stable code and a retryable flag. Most paid or state-changing requests support safe retries with an idempotency key or a client mutation ID. This page explains how to read errors and when it is safe to retry.

Response envelope#

Successful responses wrap the result in data:

JSON
{
  "data": { "id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10" },
  "request_id": "req_01J9Z3K8QF4"
}

List endpoints that paginate add a pagination object next to data. The public OpenAPI document at /api/v1/openapi.json is the one exception: it is returned unwrapped.

Error format#

Errors use the same shape on every endpoint:

JSON
{
  "error": {
    "code": "STUDIO_DOCUMENT_CONFLICT",
    "message": "Studio changed before this save could commit.",
    "retryable": false
  },
  "request_id": "req_01J9Z3K8QF4"
}
  • code is stable and safe to branch on. message is human-readable and may change.
  • retryable is true when repeating the same request later can succeed.
  • details is optional structured context, such as the conflicting version.
  • request_id is also sent as the x-request-id response header. Include it when you contact support.

Error codes#

HTTP statuscodeRetryableWhat to do
400BAD_REQUESTNoFix the request. message names the invalid field.
401UNAUTHORIZEDNoSend a valid, unexpired, unrevoked API key.
403FORBIDDENNoThe key is missing a required scope, or the resource belongs to another account.
404NOT_FOUNDNoCheck the ID. Deleted resources return 404.
409CONFLICT or a Studio conflict codeNoRe-read the resource, then retry with the current version.
429RATE_LIMITEDYesWait for the Retry-After header, then retry.
500INTERNAL_SERVER_ERRORNoRetry once later; if it persists, contact support with the request_id.
502UPSTREAM_UNAVAILABLEYesA provider is unavailable. Retry with backoff.
503SERVICE_UNAVAILABLEYesStudio is temporarily unavailable. Retry with backoff.

Studio endpoints add more specific codes. Common ones:

codeMeaning
STUDIO_DOCUMENT_CONFLICTThe document changed since the version you sent.
STUDIO_SECTION_ORDER_CONFLICTThe project's section order changed since the version you sent.
STUDIO_IDEMPOTENCY_KEY_REUSEDA client_mutation_id was reused with a different request body.
STUDIO_GENERATION_PRICE_CHANGEDThe ElevenLabs v4 price changed before generation started. Review the updated quote, then retry. Status 409.
STUDIO_GENERATION_PRICE_REJECTEDOne or more generation targets has an invalid price. Refresh the quote before retrying. Status 409.
IDEMPOTENCY_KEY_REQUIREDThe endpoint requires an Idempotency-Key header, for example POST /studio/exports.

Workflow steps report their own failures in error_code and error_message on each step. For example, STUDIO_INSUFFICIENT_BALANCE means the account ran out of words during generation.

When is it safe to retry?#

  • Network errors and timeouts. The request may or may not have been applied. Retry with the same idempotency key or client_mutation_id; never generate a new one for a retry.
  • retryable: true. Retry with exponential backoff, starting at about one second and capping at about a minute.
  • 429 RATE_LIMITED. Wait at least the number of seconds in Retry-After.
  • 409 conflicts. Do not retry blindly. Re-read the resource, decide whether your change still applies, and send it with the current version and a new mutation ID.
  • Other 4xx errors. Fix the request first.

Idempotency#

The LyricWinter API uses two idempotency mechanisms. Each endpoint in the API reference says which one it uses.

client_mutation_id in the body (most Studio writes). Send a new UUID for each intended change. Replaying the same ID with the same body returns the original result. Some creation endpoints signal a replay with 200 and idempotent_replay: true instead of 201. Reusing an ID with a different body returns 409.

For POST /studio/sections/{sectionId}/script, retry an uncertain response with the same body and client_mutation_id. The API verifies the original command receipt before accepting a replay, even if the document versions advanced; the response contains the current canonical document, not a historical snapshot. A changed body returns 409. If the original command can no longer be reconstructed after a capability update, the retry also returns 409 without importing again; read the document to confirm the outcome. This endpoint never starts paid work.

Idempotency-Key header (exports and some other endpoints). Send a unique key of up to 255 characters per logical request. Replaying the same key with the same body returns the original result with the response header Idempotency-Replayed: true. Reusing a key with a different body returns 409.

Polling long-running work#

Workflows and exports return 202 Accepted and keep running after the response. Poll the returned resource instead of repeating the start request:

  • Poll every 2–3 seconds at first, then back off to every 5–10 seconds for long runs.
  • Stop when the status is terminal. For workflows that is completed, partially_completed, failed, or cancelled; for exports it is completed, failed, cancelled, or superseded.
  • Treat signed media URLs as short-lived. Fetch fresh ones when they expire instead of storing them.