All pages
Reference
Error handling
Every failure has the same body, whatever went wrong. The codes are grouped below by what you should actually do about them.
HTTP/1.1 403 Forbidden
X-Request-Id: 0f1c8f6a-…
{
"error": {
"code": "insufficient_scope",
"message": "This API key is not permitted to perform this action."
},
"request_id": "0f1c8f6a-…"
}Fix the request
12 codesSomething about what you sent is wrong. Retrying it unchanged will fail identically.
missing_api_key401No Authorization header was sent.
invalid_request400The body could not be parsed.
validation_failed422A field is invalid — including any field that is not in the accepted shape.
unsupported_render_type422Only aesthetic_quote is available via the API.
unsupported_media_type415The upload is not a JPEG, PNG, WebP or GIF image (checked from the file bytes, not the header).
payload_too_large413The uploaded image is empty or over the 15 MB limit.
unknown_media404That media_id is not in your library, or is archived. Re-list GET /api/v1/media.
idempotency_conflict409That Idempotency-Key was already used with a different body.
integration_not_connected409No Google Drive connection for this account. Start GET /api/v1/integrations/google/connect first.
render_not_found404No render with that id for this account.
unknown_folder404The Drive folder was not found, or your connection cannot access it.
import_not_found404No import with that id for this account.
Fix the key
4 codesThe request is fine; the credential is not. Mint a new key, or re-mint it with the scope it needs.
invalid_api_key401The key is malformed or not recognised. Deliberately the same code for an unknown key and a wrong secret.
api_key_revoked401The key was revoked. Mint a new one.
api_key_expired401The key passed its expiry.
insufficient_scope403The key lacks the scope for this call. Re-mint it with the scope.
Wait — you are at a ceiling
2 codesNothing is broken. You have hit a limit and it will clear on its own. Back off and retry rather than hammering.
rate_limit_exceeded429Too many requests per minute for this key.
spend_cap_reached402This key's daily spend ceiling is used up. It rolls off per render over 24h.
Safe to retry
5 codesA transient fault on our side. Nothing was charged. Retry with backoff.
caption_prep_failed502The caption image could not be composited, so nothing was started and nothing was charged.
idempotency_in_progress409A previous request with that Idempotency-Key is still being resolved. Retry with the SAME key — a new key would create a second render. Carries Retry-After.
asset_unavailable404The finished file is not available yet, or not available at all.
internal_error500A fault on our side.
service_unavailable503Temporarily unavailable, or a dependency could not be reached.
An account setting — talk to us
4 codesNothing you can change from the client. Retrying will not help; the answer is a conversation.
tenant_inactive403The account is not active.
tier_not_eligible403The plan cannot hold API keys. Any paid plan can; Free cannot.
api_disabled403API access is switched off for this account.
quota_exceeded402The account's render allowance for the cycle is used up — or the plan does not include this render type at all. On Starter it is the latter, always.
Reserved — v1 never returns these
4 codesIn the frozen taxonomy, emitted by no shipped code path. Listed so a client switching on `code` knows the whole set exists, and marked so nobody builds handling for a case that cannot happen.
forbidden403Reserved. v1 answers an object that is not yours with 404, never 403.
render_conflict409Reserved for render mutation. v1 exposes no endpoint that mutates a render.
method_not_allowed405Wrong HTTP method. Reserved — an unmatched method is handled by the router, not this code.
concurrency_limit_reached429Reserved for a per-key in-flight ceiling. v1 does not return it.
Failures after a render is accepted
A render that was accepted and then failed does not report it as an HTTP status — the call that created it already returned 202. It arrives in render.error when you poll:
render_failedin bodyGeneration ran and did not produce a usable video.
render_timeoutin bodyGeneration exceeded its time budget.
render_rejectedin bodyThe request was refused before generation began.
render_canceledin bodyThe render was canceled.
Retrying a create safely
A create you are unsure about is the one case to be careful with. Retry it with the same Idempotency-Key and you get the original render back instead of a second one you also pay for, with an Idempotency-Replayed: true header telling you that is what happened. The same key with a different body is 409 idempotency_conflict — that is the guard working, not a bug.
A key remembers the outcome, not just the successes. If the create failed, the same key replays that same error rather than starting a second attempt — so send a new Idempotency-Key when you actually want to try again. Keys expire after 24 hours; after that the same value is free to reuse.