Errors
Every error uses one envelope:
{ "error": { "code": "quota_exhausted", "message": "Monthly quota exceeded", "details": {} } }
Code table
| HTTP | code | When |
|---|---|---|
| 400 | bad_key / invalid_request | Malformed request or document key (incl. ./..) |
| 400 | already_subscribed | You already hold that subscription |
| 401 | unauthenticated / key_expired | Missing, bad, or expired API key |
| 402 | quota_exhausted / key_budget_exhausted / insufficient_credit | Money / quota walls |
| 403 | model_not_in_plan | None of your plans include the requested model |
| 403 | reserved_key | Write/delete to a reserved kb-* document |
| 403 | model_denied / model_not_priced / byok_not_enabled / forbidden | Policy walls |
| 403 | document_too_large / document_limit_reached | Document exceeds the char cap / per-account document cap |
| 404 | model_not_found | Unknown KhaBot model key |
| 404 | document_not_found | GET/DELETE a document that doesn't exist (not billed) |
| 429 | rate_limited | RPM exceeded (retry-after header) |
| 502 | all_providers_failed | The request could not be completed upstream — retry |
| 503 | upstream_unavailable | A required service is temporarily unavailable |
Always branch on error.code, not the human-readable message.