Errors
Every API error uses the same envelope — retry only on 5xx, never on 4xx.
Envelope
All HTTP errors return a single JSON object with an error field. The shape is stable across every endpoint — type is machine-readable, message is for humans, and request_id is always included.
{
"error": {
"type": "invalid_request_error",
"code": "missing_field",
"message": "url is required",
"param": "url",
"request_id": "req_01HZX5T9Y2R7Q8KMPF3VZABCDE"
}
}Types
The type field narrows to one of six values. The HTTP status always matches the type, so you can branch on either.
| Type | HTTP | Meaning |
|---|---|---|
invalid_request_error | 400 | Malformed body, missing required field, or invalid enum value. |
authentication_error | 401 | Missing, invalid, or revoked Bearer token. |
permission_error | 403 | Key lacks the required scope, or the account is suspended. |
not_found_error | 404 | The resource you asked for doesn't exist. |
rate_limit_error | 429 | Reserved for future use — not yet enforced. |
api_error | 500 | A bug on our side. Contact support with the request_id. |
Common codes
The code field is machine-readable and stable. Branch on code, not on message.
missing_field— A required field was not provided (see param for which one).invalid_value— A field was present but outside the allowed range, format, or enum.invalid_url— The url you submitted is not a valid URL.unsupported_source— The source host is recognised but not supported (e.g. a private video).invalid_api_key— The Bearer token is malformed or doesn't match any key.key_revoked— The key was revoked — rotate from the Developers dashboard.insufficient_points— Account balance is too low to start the job. Top up and retry.duration_too_long— File exceeds the ~10h per-file duration limit. Split and submit in parts.transcription_failed— Upstream processing failed. Appears on the Transcription object, not the create response.internal_error— Unhandled server error. Safe to retry with backoff; if it persists, contact support.
Request ID
Every response — success or failure — includes a request_id in the error envelope and in the X-Request-Id header. Always include it when reporting a problem; it lets us pull the full trace in seconds.
Retries
Transcription-level errors
Async failures don't surface as an HTTP error on the create call — that call returns 200 with a job ID. Instead, the job's final state is status: "failed" with an error field on the Transcription object. Poll or subscribe to the transcription.failed webhook to handle them.
{
"id": "trs_01HZX5T9Y2R7Q8KMPF3VZABCDE",
"status": "failed",
"error": {
"code": "transcription_failed",
"message": "Upstream transcription provider returned an error after 3 attempts."
}
}