Errors
The API surfaces errors in two places:
- HTTP responses — synchronous endpoint errors (validation, auth, quota). The response body is
{ "success": false, "message": "…" }with an HTTP status code in the 4xx–5xx range. - Render status — asynchronous errors discovered while a render is being produced. The render completes with
movie.status = "error"andmovie.messagedescribing what failed. The HTTP status ofGET /v2/moviesis still200.
All error messages are short, descriptive strings. They are not stable identifiers — match on HTTP status and on the endpoint plus message family rather than on exact text.
HTTP status code summary
| Status | Meaning |
|---|---|
200 |
Request accepted. For GET /v2/movies, also check movie.status. |
400 |
Validation error in the request. |
401 |
Authentication or quota error. |
403 |
Authorisation error (role, blocked storage, invalid admin token). |
404 |
Resource (template, movie, file) not found. |
405 |
HTTP method not supported on this endpoint. |
409 |
Conflict (duplicate filename on upload, etc.). |
413 |
Payload too large (media upload > 500 MB). |
500 |
Internal error. |
Authentication errors
Returned when the request lacks a valid API key or is using one without sufficient permissions.
| Status | Message | Endpoint |
|---|---|---|
403 |
Insufficient permissions |
/v2/templates, /v2/media, POST /v2/movies (admin endpoints) |
403 |
Invalid token |
Admin-only query parameters |
To resolve: confirm the x-api-key header is present and that the key's role is at least render. Keys with role viewer cannot render.
Quota and plan errors
Returned when the account has exhausted its plan allowance.
| Status | Message | Endpoint |
|---|---|---|
401 |
You exceeded the quota of movies in your plan. Please upgrade your plan to continue. |
POST /v2/movies |
401 |
You exceeded the quota of drafts in your plan. Please upgrade your plan to continue. |
POST /v2/movies |
401 |
Movie is larger ({w}x{h}) than your plan allowance ({w}x{h}) |
POST /v2/movies |
400 |
Insufficient credits |
Render submission paths |
403 |
Storage is blocked. Add credits to continue uploading. |
POST /v2/media/file |
To resolve: top up credits or upgrade the plan. See Credits & limits.
Validation errors
Returned when the request payload is missing required fields or has the wrong shape.
| Status | Message | Endpoint |
|---|---|---|
400 |
No movie JSON received |
POST /v2/movies |
400 |
Error parsing movie JSON or the movie was empty |
POST /v2/movies |
400 |
No valid movie JSON received |
POST /v2/movies |
400 |
Project ID must be a 16-character string. Received ID: '…' (length: N) |
GET /v2/movies |
400 |
Invalid start date / Invalid end date |
GET /v2/movies |
400 |
Maximum date range is 3 months. |
GET /v2/movies |
400 |
No payload provided |
POST /v2/templates, POST /v2/media/file, PUT /v2/media/file, DELETE /v2/media/file |
400 |
Tags must be a string or an array |
POST /v2/templates |
400 |
Payload movie must be a JSON string or JSON object |
POST /v2/templates |
400 |
Template movie is not valid JSON or it's too large |
POST /v2/templates |
400 |
name is required |
/v2/media/file |
400 |
contentType is required |
POST /v2/media/file |
400 |
size is required and must be a positive number |
POST /v2/media/file |
400 |
path is required / Invalid path: no filename |
GET /v2/media/file |
400 |
destination is required |
PUT /v2/media/file |
400 |
folder is required / Invalid folder name |
/v2/media/folder |
400 |
Cannot delete root folder / Cannot delete the temp folder |
DELETE /v2/media/folder |
400 |
Folder is not empty. Delete all files first. |
DELETE /v2/media/folder |
400 |
Invalid movie status |
Render submission |
404 |
Template {id} not found |
/v2/templates, POST /v2/movies (template ref) |
404 |
File not found |
/v2/media/file |
404 |
Movie ID {id} not found |
Render submission |
403 |
Template {id} is not owned by you / Movie ID {id} is not owned by you |
POST /v2/templates, render submission |
405 |
Method not supported |
All endpoints |
409 |
A file with this name already exists. Delete it first. |
POST /v2/media/file |
409 |
A file with this name already exists in the destination folder |
PUT /v2/media/file |
413 |
File exceeds maximum size of 500 MB |
POST /v2/media/file |
Rendering errors
Surfaced asynchronously via GET /v2/movies when movie.status = "error". The movie.message field contains the underlying error. Examples seen in production:
| Family | Example message |
Trigger |
|---|---|---|
| Element validation | Scene #1 Element #2: The element type 'video' requires a 'src' property. |
A required field was missing or null. |
| Asset download | Asset fetch errors propagate from the downloader. | The element src URL is unreachable, requires authentication, or returns an unsupported media type. |
| Webpage capture | Errors from the HTML / webpage renderer. | An html element pointed at a URL that timed out, returned non-2xx, or required interaction. |
| AI generation | Errors from the upstream AI provider. | The provider declined the prompt, rate-limited the request, or returned a transient 5xx. |
| Voice synthesis | Errors from the speech provider. | Invalid voice ID, unsupported language, or empty text. |
| Subtitles | Speech-to-text transcription error. | Source audio was missing or unreadable. |
For rendering errors, the movie.success field is false even though the HTTP status is 200.
Timeouts
When a render is running for more than 15 minutes, GET /v2/movies returns movie.status = "timeout" with message = "Movie took too long to render". The original render may still eventually complete; treat timeout the same as error for client code paths.
Retry guidance
| Class | Retry strategy |
|---|---|
400 validation |
Do not retry. Fix the payload. |
401 quota |
Do not retry until credits are topped up. |
403 auth |
Do not retry. Fix the key or role. |
404 not found |
Do not retry. Confirm the ID. |
409 conflict |
Do not retry blindly. Resolve the conflict (rename, delete the existing file). |
500 internal |
Retry with exponential backoff, up to 3–5 attempts. |
movie.status = "error" |
Inspect the message. Re-submit a fixed payload if the cause was client-side. |
movie.status = "timeout" |
Re-submit the same job; treat as a transient failure. |