Errors
Every error from the Video API endpoints uses the same JSON shape:
{
"error": {
"code": "...",
"message": "..."
}
}The HTTP status tells you the class of the problem; error.code is a stable string you can branch on in code. Always match on error.code rather than parsing error.message.
Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A required parameter is missing or a value is invalid |
| 400 | invalid_callback_url | callback_url is not HTTPS or points to a private network (blocked by SSRF checks) |
| 400 | references_conflict | frame_images and input_references were sent in the same request (mutually exclusive) |
| 400 | too_many_references | input_references exceeds the limits (images > 9 / audio > 3 / video > 1) |
| 400 | cancel_not_supported | The upstream provider cannot interrupt this job |
| 400 | cancel_failed | The job is already in a terminal state and cannot be cancelled |
| 401 | unauthorized / invalid_api_key | Authentication failed |
| 401 | upstream_auth_failed | Upstream provider authentication failed |
| 402 | insufficient_credits | Not enough balance to accept the job |
| 404 | not_found | The job does not exist, or you do not have access to it |
| 404 | model_not_found | The requested model does not exist |
| 429 | rate_limited | Too many requests (polling rate limit or upstream rate limit) |
| 502 | upstream_error / route_error | Upstream provider error / routing failure |
| 500 | internal_error | Unexpected internal error |
references_conflict and too_many_references are request-body validation errors — see Create video for the exact limits. cancel_not_supported and cancel_failed are described on Cancel video. not_found is returned for both an unknown job and a job owned by a different API key; the two cases are intentionally indistinguishable.
402 Insufficient credits
insufficient_credits is returned only when you create a job (POST /v1/videos). When pre-authorization is enabled, ofox estimates the cost from the requested resolution and duration before accepting the job. If the estimate exceeds your balance, the request is rejected immediately — no job record is created and nothing is charged.
{ "error": { "code": "insufficient_credits", "message": "..." } }insufficient_credits is the only 402 code the Video API returns. Handle this single code, top up your balance, and retry.
429 Rate limiting
rate_limited covers both the per-key polling limit on GET /v1/videos/{id} and upstream rate limits. When you hit the polling limit, the response carries a Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json
{ "error": { "code": "rate_limited", "message": "..." } }Respect the Retry-After header and back off before retrying. If you are polling frequently, switch to webhook notifications so ofox pushes the terminal state to you instead — this avoids the polling limit entirely. Job creation (POST) and cancellation (DELETE) are not affected by the polling limit.