Errors
The API uses conventional HTTP status codes, and every error carries the same JSON body: a stable machine-readable code for your program and a message for your logs.
The error body
Error response
{
"error": {
"code": "insufficient_credits",
"message": "This job needs 3 credits and you have 1."
}
}Branch on error.code, not on the message. Messages are for humans and may be reworded; codes are part of the versioned contract and will not change meaning.
Status codes
| Status | Meaning |
|---|---|
| 200 | Request succeeded (also an idempotent replay of a previous submission). |
| 202 | Job accepted and queued. |
| 302 | Redirect to a signed download URL. |
| 400 | invalid_request: a parameter is missing or malformed. Fix the request; retrying unchanged will fail again. |
| 401 | unauthorized: missing, malformed or revoked API key. |
| 402 | insufficient_credits: top up, then retry. |
| 403 | forbidden: the key is valid but not allowed to do this. |
| 404 | not_found: no such job on this account. Ids are account-scoped. |
| 409 | conflict: the job already finished, or has no result yet. |
| 413 | payload_too_large: the image exceeds 10 MB. |
| 415 | unsupported_media_type: not a JPEG, PNG, WebP or AVIF. |
| 429 | rate_limited: wait Retry-After seconds, then retry. |
| 500 | server_error: our fault. Safe to retry with the same Idempotency-Key. |
Handling failures
| Parameter | Type | Description |
|---|---|---|
| 4xx (except 429) | don't retry | The request itself is wrong. Retrying unchanged gives the same answer. Fix and resend. |
| 429 | retry after backoff | Wait the Retry-After seconds. Never busy-loop on it. |
| 5xx | retry with idempotency | Transient. Retry with the same Idempotency-Key so a request that actually landed isn't charged twice. |
| job.failed | no charge | Processing failures refund the job's credits automatically; the job's error field says what went wrong. |