Errors

Public API errors

Every error response is an RFC 9457 Problem Details document (application/problem+json):

  • code is the stable machine string to branch on. type links to this page (https://developers.synthesia.io/docs/errors#<code>) — it's documentation, not an identifier, and its URL may change.
  • detail is human-readable and may change without notice; each code below shows example
    messages ({braces} mark request-specific values).
  • requestId (also the Request-Id header) identifies the request in Synthesia's logs —
    include it when contacting support.
  • New codes may appear over time; a rare unmapped 4xx surfaces as http_<status>, and an
    unexpected 5xx keeps its status with code internal. Handle any response you don't
    recognize by its HTTP status.
Statuscodetitle
400bad_requestBad request
400validation_errorInvalid request
401api_key_expiredAPI key expired
401unauthenticatedUnauthenticated
402feature_not_in_planFeature not in plan
402no_creditNo credit
402payment_requiredPayment required
402quota_exceededQuota exceeded
402user_credit_limit_reachedUser credit limit reached
403connection_requiredConnection required
403forbiddenForbidden
403insufficient_scopeInsufficient scope
403organization_disabledOrganization disabled
404not_foundNot found
404unknown_referenceUnknown reference
405method_not_allowedMethod not allowed
409conflictConflict
413payload_too_largePayload too large
415unsupported_media_typeUnsupported media type
429concurrency_limitConcurrency limit exceeded
429rate_limitedRate limit exceeded
500internalInternal error
503admission_unavailableAdmission temporarily unavailable
503service_unavailableService unavailable
504timeoutUpstream timeout

bad_request

Bad request — status 400 — type

The request could not be parsed as sent — usually a body that is not JSON. Fix the request before retrying; an unchanged retry fails the same way.

Example detail messages:

  • The request body is missing or null. Send a JSON object.
  • The request body is not valid JSON. Send a JSON object.
  • The request body was not sent as JSON. Set the Content-Type header to application/json.

validation_error

Invalid request — status 400 — type

One or more request fields were rejected. Fix the fields detail lists and resend; an unchanged retry fails the same way.

For a rejected request body, detail lists each rejected field as path: message, joined with ; ; other validation denials use the standalone messages below.

Example detail messages:

  • Could not establish a media connection to the LiveKit server at livekitUrl. Its WebRTC ports (UDP/TCP) or a TURN server must be reachable from the internet; HTTP-only tunnels such as Cloudflare quick tunnels or ngrok carry signalling but not media.
  • Not a valid {concept} id.
  • One or more fields were rejected.
  • The supplied livekitToken cannot be used to join the room.
  • query.cursor: Not a cursor this list issued. Omit it to start from the first page.

api_key_expired

API key expired — status 401 — type

The API key is genuine but past its expiry date. Not retryable with this key — create a new key and use it instead. The WWW-Authenticate: Bearer header carries error="invalid_token".

Example detail messages:

  • Your API key has expired. Create a new key and retry with it.

unauthenticated

Unauthenticated — status 401 — type

The request carried no usable API key. Send your key as Authorization: Bearer <key>. An unknown or revoked key is reported only as invalid; an expired key answers api_key_expired instead. The WWW-Authenticate: Bearer header carries realm alone when no key was sent, error="invalid_request" for an Authorization scheme other than Bearer, and error="invalid_token" for a rejected key.

Example detail messages:

  • Invalid API key.
  • Provide your API key in the Authorization header.
  • Provide your application's OAuth access token in the Authorization header.
  • Unsupported Authorization scheme. Send your API key as 'Authorization: Bearer '.
  • Unsupported Authorization scheme. Send your application's OAuth access token as 'Authorization: Bearer '.

feature_not_in_plan

Feature not in plan — status 402 — type

Your workspace's plan does not include a feature this endpoint requires; features names it. Not retryable — upgrade the plan or contact your account manager.

Example detail messages:

  • Your plan does not include interactive avatars — upgrade to use this API.
  • Your plan does not include the '{feature}' feature.

no_credit

No credit — status 402 — type

Your workspace has no credit remaining for the metered feature this request consumes. Not retryable until the balance is positive again — top up or upgrade your plan.

Example detail messages:

  • Your plan has no interactive avatar credits. Top up or upgrade to create interactive avatars.

payment_required

Payment required — status 402 — type

The request was declined for billing reasons, such as exhausted credits. Resolve the billing condition, then retry.

quota_exceeded

Quota exceeded — status 402 — type

A usage quota in your plan is used up. Not retryable until your quota is increased or replenished — upgrade your plan or contact your account manager.

Example detail messages:

  • Your session quota is exhausted.

user_credit_limit_reached

User credit limit reached — status 402 — type

You have run out of your monthly credit limit for the metered feature this request consumes, while your workspace still has credit. Not retryable until the limit resets — ask a workspace admin to raise it.

Example detail messages:

  • You have run out of your monthly credit limit. Ask a workspace admin to raise it, or wait for it to reset.

connection_required

Connection required — status 403 — type

The access token is valid, but the Synthesia account behind it has no active connection for your application: it was never completed, was disconnected, or expired after 30 days without use. Call POST /connections with the same token, then retry. If the token has expired and refreshing it fails, re-authorize the user first.

Example detail messages:

  • This Synthesia account has no active connection for your application. Call POST /connections, then retry.

forbidden

Forbidden — status 403 — type

Your API key is valid but not permitted to do this — the resource may belong to another workspace, or your account may lack the required permission. If you believe you should have access, check with your workspace admin.

Example detail messages:

  • This endpoint accepts an OAuth access token issued to your application, not an API key.

insufficient_scope

Insufficient scope — status 403 — type

Your API key or access token does not carry the scope this endpoint requires; detail names it, as does scope in the WWW-Authenticate: Bearer error="insufficient_scope" header. Use or create a key with that scope, or re-authorize to request it — retrying with the same credential fails the same way. A stronger scope on the same resource also works (:write satisfies :read); Scopes lists every scope and the endpoints that need it.

Example detail messages:

  • Your API key does not have the '{scope}' scope this endpoint requires.
  • Your access token does not have the '{scope}' scope this endpoint requires.

organization_disabled

Organization disabled — status 403 — type

The access token is valid, but the user's Synthesia organization has not enabled the integration for your application. Keep the access and refresh tokens and do not re-authorize: consent was given and only the organization's setting blocks the call. Ask the user to contact their Synthesia admin, then retry the same request once it is enabled.

Example detail messages:

  • This user's Synthesia organization has not enabled the integration for your application. Ask a Synthesia admin in the organization to enable it, then retry the same request; no new authorization is needed.

not_found

Not found — status 404 — type

Nothing exists at this URL. Check the path and any resource id in it.

unknown_reference

Unknown reference — status 404 — type

The request referenced a resource that does not exist or is not accessible to your workspace. Fix the referenced id and resend.

Example detail messages:

  • One or more of avatarIds does not exist or is not accessible.
  • The referenced avatar, outfit or person does not exist or is not accessible.

method_not_allowed

Method not allowed — status 405 — type

The URL exists, but not for this HTTP method. The Allow header lists the methods it supports.

conflict

Conflict — status 409 — type

The request conflicts with the resource's current state. Fetch the resource, reconcile, and resend.

Example detail messages:

  • The LiveKit room was closed or deleted, or the avatar's participant was removed or replaced by another participant with the same identity, while the session was starting. Retrying against a room that is no longer open fails the same way: start the session in an open room, with a livekitToken for that room, and keep it open until the session starts. If another participant joined with the livekitToken's identity, give the avatar an identity of its own.

payload_too_large

Payload too large — status 413 — type

The request body exceeds the size this endpoint accepts. Reduce the payload and resend.

unsupported_media_type

Unsupported media type — status 415 — type

The request's Content-Type is not one this endpoint accepts. Send the body as application/json unless the endpoint documents otherwise.

concurrency_limit

Concurrency limit exceeded — status 429 — type

Your plan's ceiling on concurrently running sessions is reached. Retryable — end an active session or wait for one to finish, honoring Retry-After when present.

Carries Retry-After when Enact sends a wait interval. When known, detail leads with the caller's plan numbers and keeps the guidance to end or wait for a session.

Example detail messages:

  • Too many sessions are running concurrently for your plan. End an active session or wait for one to end.

rate_limited

Rate limit exceeded — status 429 — type

Too many requests in the current window. Retryable — back off for the Retry-After interval, then resend the same request.

The facade's own denials carry RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset-At and Retry-After headers; a domain's 429 carries at most Retry-After.

Example detail messages:

  • Too many requests. Retry after the interval in the Retry-After header.

internal

Internal error — status 500 — type

Something unexpected failed on Synthesia's side. Usually safe to retry; for a request that creates a resource, check whether the operation went through first. If it persists, contact support and quote the requestId.

Example detail messages:

  • An unexpected error occurred.

admission_unavailable

Admission temporarily unavailable — status 503 — type

A billing or rate decision this request needs could not be obtained, so it was denied rather than admitted unchecked. Transient — retry with backoff, honoring Retry-After when present.

Example detail messages:

  • Admission is temporarily unavailable. Retry shortly.

service_unavailable

Service unavailable — status 503 — type

A service this request needs is temporarily unavailable. Transient — retry with backoff, honoring Retry-After when present and any instruction in detail. If it persists, contact support and quote the requestId.

Example detail messages:

  • Authentication is temporarily unavailable. Retry shortly.
  • Plan features for this request could not be verified. Retry shortly.
  • Temporarily unable to create an interactive avatar. Retry the same request with regenerate off.
  • Temporarily unable to read credits. Retry shortly.
  • Temporarily unable to read the plan. Retry shortly.
  • Temporarily unable to start a session. If you retry, reuse the same livekitUrl and livekitToken.
  • The session could not be started. Retry shortly.

timeout

Upstream timeout — status 504 — type

The request did not finish within its deadline. The underlying operation may still have gone through — follow the guidance in detail on how to retry or poll safely, otherwise retry with backoff.

Example detail messages:

  • Authentication is temporarily unavailable. Retry shortly.
  • Plan features for this request could not be verified. Retry shortly.
  • The request did not complete within its {deadline}s deadline.
  • The session did not start before the deadline. It may still start. If you retry, reuse the same livekitUrl and livekitToken.
  • Timed out reading credits. Retry shortly.
  • Timed out reading the plan. Retry shortly.
  • Timed out waiting for the avatar status. Generation may still be running; repeat the same request with regenerate off to poll.
  • Timed out waiting for the session to start. It may still start. If you retry, reuse the same livekitUrl and livekitToken.