Concepts
Errors
One envelope, seven codes, and a requestId on everything — never a stack trace, never HTML. A failed call is never charged.
The envelope
Every error is JSON with a stable code, a human message, and a requestId (also in the x-request-id header) you can quote at us to trace the exact call.
402 Payment Required
{
"error": {
"code": "insufficient_credits",
"message": "This call costs 10 credits; your balance is 3."
},
"requestId": "req_9f2c41d0aa8b7e6c5d3f1a2b"
}Every code
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
| unauthorized | 401 | Missing, malformed, revoked, or unknown API key. | Fix the Authorization header — retrying the same key won't help. |
| invalid_request | 400 | The body failed validation; the message names the exact field. | Correct the request and resend. |
| insufficient_credits | 402 | Your balance can't cover this call. Nothing was charged. | Top up (or arm auto-recharge), then resend. |
| unprocessable | 422 | Valid request, but the input couldn't be processed (e.g. an unreadable file). | Resend with a different input; the same input will fail again. |
| rate_limited | 429 | Per-key rate limit for this endpoint exceeded. | Wait Retry-After seconds, then resend. |
| inference_unavailable | 503 | Every model rail for this capability is briefly unavailable. | Safe to retry with backoff — the call was never charged. |
| server_error | 500 | Something failed on our side. Never charged. | Retry with backoff; quote the requestId if it persists. |
Retry discipline
rate_limited carries Retry-After — honor it. inference_unavailable and server_error are safe to retry with exponential backoff, because a failed call is never billed. The 4xx codes are yours to fix — retrying the same request reproduces the same error.