Errors and retries
Errors are returned as JSON with a stable code, a human-readable message and the request_id:
{
"error": {
"code": "credits_exhausted",
"message": "The workspace has insufficient credits.",
"request_id": "req_8f3a1c..."
}
}
Validation errors also include fields. We never return JSON with an image content type, and never fall back to a different output format.
Codes
| HTTP | Code | Meaning | Retry? |
|---|---|---|---|
| 400 | invalid_json |
The body is not valid JSON. | No, fix the request. |
| 401 | unauthorized |
Missing, unknown, expired or revoked key. | No. |
| 402 | credits_exhausted |
No credits left in any balance. | After adding credits. |
| 403 | forbidden |
Missing permission, service or referrer restriction, or suspended workspace. | No. |
| 404 | not_found |
Resource not found in your workspace. | No. |
| 409 | conflict |
The request conflicts with current state. | No. |
| 413 | payload_too_large |
Body over the size limit. | No. |
| 415 | unsupported_format |
Requested output format is not supported. | No. |
| 422 | validation_error |
One or more fields are invalid; see fields. |
No. |
| 429 | rate_limited |
Too many requests. | Yes, after Retry-After seconds. |
| 500 | generation_failed / internal_error |
We could not complete the request. You were not charged. | Yes, with backoff. |
| 503 | service_unavailable |
Temporarily unavailable. You were not charged. | Yes, with backoff. |
Retrying
Retry only 429, 500 and 503. Use exponential backoff with jitter, for example 1s, 2s, 4s and 8s, plus or minus 20%, up to five attempts. Honour Retry-After when present.
Failed requests are never charged, so retrying a failed request cannot double-charge you. A request that succeeded is charged once, even if you did not receive the response; check the request_id in your usage log before retrying non-idempotent work.
Request ids
Every response, successful or not, carries X-Request-Id. Include it when contacting support.