Error shape
Errors are structured: the body carries a machine-readable error.metadata.reason alongside the human message, so your handler can branch without string-matching.
{
"error": {
"code": 402,
"message": "Credit balance exhausted. Top up or enable metered overage.",
"metadata": { "reason": "credit_exhausted" }
}
}Error reference
| Status | Reason | What to do |
|---|---|---|
| 402 | credit_exhausted | Balance is zero. Top up under Dashboard → Credits or enable metered overage (paid plans). See Credits & billing. |
| 402 | overage_cap_exhausted | Prepaid balance and metered cap both used. Raise the cap under Dashboard → Apps or top up. |
| 403 | tier_required | Capability needs a higher plan (e.g. Fusion on Pro+). Upgrade from Pricing. |
| 403 | guardrail_block | Request blocked by a key or app guardrail. Check Dashboard → Guardrails. |
| 429 | key_rate_limit | This key exceeded its plan's requests/minute. Honor Retry-After or upgrade — see Rate limits. |
| 429 | ip_rate_limit | The shared 120/min per-IP ceiling was hit across keys on your egress IP. Honor Retry-After; for shared-office NAT, ask about dedicated throughput. |
Rate-limit errors
Every 429 carries a Retry-After header (seconds until the sliding window frees up) and names which limit you hit in error.metadata.reason:
HTTP/1.1 429 Too Many Requests
Retry-After: 42
{
"error": {
"code": 429,
"message": "Rate limit exceeded. Slow down or upgrade your plan for a higher RPM cap.",
"metadata": { "reason": "key_rate_limit", "retry_after": 42 }
}
}The full budget table and fair-use policy live in Rate limits & fair use.