Errors and limits
Every error uses one envelope: an error object with a coarse type, a specific code, a human-readable message, an optional param, and the request_id that also appears in the X-Request-Id response header. Branch on type for control flow and on code for detail; never parse message.
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-Request-Id: req_3f9c2a1b7e6d5c4b3a2f1e0d
{
"error": {
"type": "insufficient_balance",
"code": "insufficient_balance",
"message": "Insufficient balance: this request costs $0.0250 but your balance is $0.0100. Top up in the console.",
"request_id": "req_3f9c2a1b7e6d5c4b3a2f1e0d"
}
}Types and HTTP status
| type | HTTP | Meaning |
|---|---|---|
invalid_request_error | 400 | Malformed or invalid body/query. `param` names the offending field when known. |
authentication_error | 401 | Missing, malformed, revoked or expired API key. |
insufficient_balance | 402 | Wallet cannot cover the quoted price. Top up or enable auto-recharge. |
permission_error | 403 | Account is paused, suspended or closed. |
not_found | 404 | No such job / model / endpoint. |
idempotency_conflict | 409 | Idempotency-Key reused with a different request body. |
content_blocked | 422 | Prompt, input image or generated output failed the content policy. Refunded. |
rate_limit_error | 429 | Per-key request rate or per-account concurrency limit exceeded. See Retry-After. |
capacity_error | 503 | Temporarily out of GPU capacity or moderation provider unavailable. Retry with backoff. |
api_error | 500 | Unexpected server error. Quote the request id to support. |
Common codes
| code | Meaning |
|---|---|
invalid_body / invalid_json / invalid_content_type | Body failed validation; must be JSON. |
model_unavailable | The model id is unknown, disabled or does not support this operation. |
invalid_api_key | Bearer token missing or not recognized. |
insufficient_balance | See 402 above. |
account_paused / account_suspended / account_closed | Account status prevents new jobs. |
content_blocked_prompt | Prompt or negative prompt violates the content policy. |
content_blocked_input | An input image violates the content policy. |
content_blocked_output | The generated output failed the output gate; deleted, refunded, strike recorded. |
rate_limited | Token bucket exhausted for this key (RateLimit-* headers show the budget). |
concurrency_limit | Too many in-flight jobs for the account (default 5). |
capacity | No GPU capacity right now; retry after Retry-After seconds. |
Rate limits
Each API key has a token bucket sized to the account’s requests-per-minute limit (default 60, refilling continuously). Every response includes RateLimit-Limit and RateLimit-Remaining; a 429 includes Retry-After in seconds. Separately, each account may have at most a set number of jobs in flight (max_concurrent_jobs, default 5) — exceeding it returns 429 with code = concurrency_limit. Both limits are visible on GET /v1/account and can be raised on request.
Idempotency
Send an Idempotency-Key header (any string up to 200 characters, unique per request) on POSTs. If a request with the same key and body was already accepted, the original job is returned with Idempotency-Replayed: true and you are not charged twice. Reusing a key with a different body returns 409 idempotency_conflict. Keys are scoped to your account and remembered for 24 hours.
Retry guidance
429and503: retry with exponential backoff starting atRetry-After.5xxon a POST: retry with the sameIdempotency-Keyso a job is never created twice.402: stop and top up (or turn on auto-recharge in Billing).422 content_blocked: do not retry the same content; see the content policy.