Every non-200 response follows the same shape, so you can handle errors generically and branch on code only when you need to.
{
"error": {
"code": "invalid_request",
"message": "\"messages\" must be a non-empty array.",
"retry_after_seconds": 12
}
}retry_after_seconds is only present on 429. message is meant for a developer reading logs, not for showing to an end user verbatim.
| Status | code | Meaning | Retry? |
|---|---|---|---|
| 400 | invalid_json | Request body isn’t valid JSON | Fix the request, then retry |
| 400 | invalid_request | A field failed validation (bad type, out-of-range value, empty messages array, etc.) — see message for which one | Fix the request, then retry |
| 401 | missing_api_key | No Authorization header present | Add the header, then retry |
| 401 | invalid_api_key | Key not recognized or has been revoked | Check the key in your dashboard |
| 429 | rate_limited | Per-key rate limit hit | Wait retry_after_seconds, then retry |
| 502 | upstream_unavailable | Both the primary and fallback models failed to respond | Safe to retry immediately or with light backoff |
| 503 | capacity_exceeded | Account-wide capacity safeguard is active (see Rate Limits) | Retry after a short backoff |
A request that gets safety-intercepted (crisis language, disallowed content) is not an error — it's a normal 200 response with flags.crisis or flags.blocked set and a fixed message in reply. See API Reference. Treat a non-200 status strictly as "something about the request or the service itself failed," not as a content-moderation signal.
4xx errors mean something about your request needs to change before retrying (bad auth, bad body, rate limit). 5xx errors (502, 503) mean the problem is on the service side and the same request may well succeed on retry — safe to build simple retry logic around, see Examples.