Skip to main content

Errors

Errors are JSON with an error key:

{ "error": "Content not found" }

Two endpoints deviate, and both are noted below.

Status codes

StatusMeaningWhat to do
400Validation failed, or a plan limit was exceededRead error; it names the field or limit. Do not retry unchanged.
401Key missing, malformed, invalid or revokedCheck the key with GET /api-keys/introspect.
402Not enough creditsTop up, or check GET /users/credits before a batch.
403Key is valid but lacks a scopeMint a key with the scope in required.
404No such resource for this key's ownerAnother user's resource is indistinguishable from one that doesn't exist.
409Conflict with in-flight workSee below — usually resolvable by being explicit.
429Rate limitedWait Retry-After seconds.
5xxServer-side failureRetry with backoff. If it persists, it's ours.

401 — authentication

{ "error": "Invalid or revoked API key" }

The key is missing, malformed, expired from your account, or revoked. Confirm it independently with GET /api-keys/introspect, which needs no scope — that separates "the key is wrong" from "the request is wrong". See Authentication.

403 — insufficient scope

{
"error": "insufficient_scope",
"required": ["write"]
}

required lists what the endpoint needs. Scopes are fixed for a key's life, so this means minting a new key — see Scopes.

409 — conflicts

Two situations produce it.

Editing content while it is generating. PUT /contents/{id} refuses, because the edit would silently discard the running job's work:

{
"error": "This content is currently being generated. Editing it will cancel the generation in progress.",
"code": "generation_in_progress"
}

Resend with "cancel_generation": true to cancel the job and apply the edit.

Publishing something already being published. POST /contents/upload/{id} refuses a second dispatch while one is in flight, so a client that retries after a timeout doesn't post the same video twice. It clears once the first dispatch passes the stall threshold, so genuine recovery still works.

429 — rate limits

Carries Retry-After in seconds. Honour it rather than retrying immediately — see Rate limits.

Endpoints that deviate

  • GET /contents/{id}/versions returns {"message": ...} on 404, not {"error": ...}. Handle both keys if you parse error bodies generically.
  • GET /subscription/current wraps its payload in success and returns {"success": false, "error": ...} on failure.

Retrying safely

  • Retry: 429 (after Retry-After) and 5xx, with exponential backoff.
  • Don't retry unchanged: 400, 401, 403, 404 — they will fail the same way.
  • Careful with 409 on upload: a naive retry loop is what that guard exists to catch. Poll task-status to find out what actually happened before dispatching again.