Errors
Every failed request returns the same envelope: an HTTP status and a JSON body with a machine-readable code. Branch on error.code, never on error.message — codes are stable, messages are not.
The code does not repeat the HTTP status. 404 Not Found arrives with code 400404; a request without the Authorization header arrives with HTTP 400 and code 100101. Read the status and the code independently.
{
"error": {
"code": 400301,
"message": "invalid uuid format",
"detail": "see https://en.wikipedia.org/wiki/Universally_unique_identifier"
}
}The API returns that link itself. It covers only one of the accepted notations: paths also take a UUID without dashes and a base58 form 21–22 characters long, so a value rejected with this code is not necessarily a malformed UUID.
Validation errors carry invalid_params, one entry per rejected field:
{
"error": {
"code": 400400,
"message": "request parameters didn't validate",
"invalid_params": [
{ "index": 0, "name": "privacy_type", "reason": "oneof", "message": "anywhere nowhere custom" }
]
}
}The same code arrives without invalid_params when a required query parameter is missing — the parameter name is then inside message:
{ "error": { "code": 400400, "message": "Parameter 'from' not found" } }Server errors use a different shape: path and timestamp instead of detail.
{
"error": {
"code": 500500,
"path": "/v1/videos",
"message": "no message available",
"timestamp": "2026-09-24T09:25:48.540408556Z"
}
}An empty request body is reported separately, with code 1 and message io error.
Fields:
| Field | Type | Description |
|---|---|---|
error.code | number | Machine-readable code. Does not repeat the HTTP status — the full list is below. |
error.message | string | Short human-readable explanation, suitable for logs. Not stable: do not branch on it. |
error.detail | string | Optional. Additional context: the JSON parse position, the rejected value, or a reference link. |
error.invalid_params | array | Optional. Per-field breakdown of a validation failure. Each entry has index, name (the field), reason (required, oneof, notempty_if, not exists, …) and message with the accepted values. |
error.path | string | 5xx only. The path that failed. |
error.timestamp | string | 5xx only. RFC 3339, UTC. |
X-Request-ID. Successful responses and errors 400, 401 and 500 carry this response header — quote it when contacting support. It is not sent on 404 and 405.
HTTP status code summary
| Code | Name | Description |
|---|---|---|
| 200 | OK | Request succeeded. The response body contains the requested object. |
| 201 | Created | Resource was created. The response body contains the new object. |
| 204 | No Content | Request succeeded; the endpoint has no body to return (typically after a DELETE). |
| 400 | Bad Request | Malformed request: invalid JSON, unparseable identifier, value outside the allowed set. Also returned when the Authorization header is missing — code 100101. |
| 401 | Unauthorized | The token is invalid, revoked, or belongs to another workspace. |
| 402 | Payment Required | The plan or balance does not cover this operation. Not reproduced during verification. |
| 403 | Forbidden | The token is authenticated but lacks permission. Not reproduced during verification. |
| 404 | Not Found | The object does not exist, or is not visible to this token. Arrives with code 400404. |
| 405 | Method Not Allowed | The path does not support this method. Arrives with code 400405. |
| 409 | Conflict | State conflict; used by Speak. Not reproduced during verification. |
| 422 | Unprocessable Entity | The resource is not ready yet; used by Speak. Not reproduced during verification. |
| 429 | Too Many Requests | Rate limit. Not reproduced: 50 parallel requests passed without one. The API sends neither RateLimit-* nor Retry-After. |
| 5xx | Server Error | Unexpected server error. Safe to retry with exponential backoff; contact support if it persists. |
Numeric codes returned in error.code. A dash in the Name column means the code has no machine-readable name assigned yet — branch on the number. The Retry column says whether repeating the identical request can help.
Authentication & access codes (1xxxxx)
| Code | HTTP | Name | Retry | Description |
|---|---|---|---|---|
| 1 | 400 | IO_ERROR | no | The request body could not be read — usually an empty or truncated payload, or a dropped connection. |
| 100101 | 400 | AUTH_AUTHORIZATION_HEADER_NOT_FOUND | no | The Authorization header is missing. Note the status: 400, not 401, and no WWW-Authenticate header is sent. |
| 100102 | 401 | UNAUTHORIZED | no | The token is invalid, revoked, or expired. A missing header is 100101 instead. Issue a new token. |
| 100103 | 403 | ACCESS_DENIED | no | The token is valid but does not grant access to this resource or scope. Check the token permissions. |
| 100104 | 400 | INVALID_USERNAME_OR_PASSWORD | no | The credentials provided to the sign-in endpoint do not match any account. |
| 100105 | 400 | INVALID_CONFIRMATION_TOKEN | no | The email-confirmation token is unknown or expired. Request a new one. |
| 100106 | — | LIMIT_REACHED | later | A per-workspace quota has been hit. Check the plan. |
| 100107 | 403 | USER_IS_NOT_OWNER | no | The action requires workspace-owner privileges. |
Bad request & validation codes (4xxxxx)
| Code | HTTP | Name | Retry | Description |
|---|---|---|---|---|
| 400101 | 400 | JSON_SYNTAX_ERROR | no | The request body is not valid JSON. detail carries the offending character and its context. |
| 400102 | 400 | JSON_UNMARSHAL_TYPE_ERROR | no | A field has an unexpected type — for example a string where a number is required. |
| 400201 | 400 | HAS_ALREADY_BEEN_TAKEN | no | A uniqueness constraint was violated. |
| 400202 | 400 | EMAIL_IS_ALREADY_TAKEN | no | An account with this email already exists. |
| 400203 | 400 | NAME_IS_ALREADY_TAKEN | no | An entity with this name already exists in the current scope. |
| 400204 | 400 | INVITATION_IS_ALREADY_EXIST | no | An invitation has already been sent to this recipient. |
| 400205 | 400 | INVITATION_IS_ALREADY_APPROVED | no | The invitation has already been accepted. |
| 400206 | 400 | BILLING_ACCOUNT_IS_ALREADY_EXIST | no | A billing account is already attached to this workspace. |
| 400207 | 400 | NOT_ENOUGH_MONEY | later | The workspace balance is insufficient for this operation. |
| 400208 | 400 | NO_BILLING_ACCOUNT | no | The workspace has no billing account yet. |
| 400209 | 400 | NO_PAYMENT_METHOD | no | No payment method is configured on the billing account. |
| 400210 | 400 | NOT_ENOUGH_REQUIRED_PRODUCTS | no | The current plan is missing a product this operation depends on. |
| 400211 | 400 | NOT_ALLOWED_ADDITIONAL_FOR_TRIAL | no | Add-ons cannot be purchased on a trial plan. |
| 400212 | 400 | SUBSCRIPTION_NOT_PAID | later | The workspace has unpaid invoices. |
| 400213 | 400 | EMAIL_NOT_CONFIRMED | later | The user's email address has not been confirmed yet. |
| 400214 | 400 | EMAIL_NOT_FOUND | no | No account is associated with the given email. |
| 400215 | 400 | RESET_TOKEN_NOT_FOUND_OR_EXPIRED | no | The password-reset token is unknown or expired. |
| 400216 | 400 | NOT_ALLOWED_ORDER_FIELD | no | The order parameter names a field this endpoint cannot sort by. The direction is case-sensitive: title.DESC is rejected, title.desc is not. |
| 400236 | 400 | — | no | The referenced folder does not exist — for example parent_id in Copy video. Carries invalid_params; the folder is checked before the video. |
| 400301 | 400 | — | no | The identifier could not be parsed in any accepted notation: UUID with dashes, UUID without dashes, or base58. Not a statement about the object existing. |
| 400302 | 400 | — | no | The identifier is 21–22 characters long but carries a character outside the base58 alphabet (O, I, l). A leading 0 is padding and is accepted; a wrong character anywhere else is not. |
| 400400 | 400 | — | no | Validation failed, or a required query parameter is missing. Two shapes: with invalid_params and without — see above. |
| 400404 | 404 | — | no | The object does not exist or is not visible to this token. The most common error in practice. |
| 400405 | 405 | — | no | The path does not support this method. Check the method on the endpoint page. |
Other error codes (402 / 404 / 409 / 422 / 500)
| Code | HTTP | Name | Retry | Description |
|---|---|---|---|---|
| 402402 | 402 | VALIDATION_ERROR | no | Carried over from the previous catalogue. Could not be reproduced, and the one example that showed it turned out to be copied from another endpoint. Real semantics require confirmation — use 400400 as the validation code. |
| 404404 | 404 | NO_SUCH_ENTITY | no | Listed in this catalog. In practice a missing object returns 400404. |
| 409293 | 409 | — | later | State conflict on a Speak transcript. Known only from the Speak response example; not reproduced. |
| 422100 | 422 | — | yes | A Speak transcript is not ready yet. Known only from the Speak response example; not reproduced. |
| 500500 | 500 | INTERNAL_SERVER_ERROR | yes | Internal server error. Reproduced on GET /v1/videos?page=0. Retry with exponential backoff; if the same parameters fail repeatedly, retrying will not help. |
Handling errors
- Retries.
5xxresponses and network timeouts are safe to retry with exponential backoff; cap the attempts at five. Other4xxresponses should not be retried — fix the request first. - Rate limits. The API sends neither
RateLimit-*norRetry-After. The developer guide states 10 requests per second and 300 per minute, but 50 parallel requests passed without a429, so treat the published figure as unconfirmed and pause at least 5 seconds before repeating after one. - Validation. Parse
error.invalid_params—nameis the field to fix andmessagelists the accepted values. Wheninvalid_paramsis absent, the parameter name is insidemessage. - Identifiers.
400301and400302mean the identifier could not be parsed, not that the object is missing. A missing object is400404. - Repeating a POST.
Idempotency-Keyis not supported in any documented form. Assume that repeating aPOSTafter a timeout creates a second object; check with a list request before retrying. - Logging. Log
error.codeandX-Request-ID, noterror.message: codes are stable, messages are not.
Codes and shapes on this page were verified against the production API on 2026-09-24. Rows marked as not reproduced are carried over from the previous catalog or from response examples and still need confirmation.