Errors & Rate Limits
NavyAI uses standard HTTP status codes and a consistent JSON error body across every endpoint. This page lists the codes you can expect, the error shape, and how rate limiting works.
Error response shape
All non-streaming errors return a body that looks like this:
1{
2 "error": {
3 "message": "Human-readable description of what went wrong.",
4 "type": "invalid_request_error",
5 "code": "missing_required_parameter",
6 "param": "prompt"
7 }
8}message— Always present. Safe to surface in UI.type— Coarse-grained category:invalid_request_error,authentication_error,permission_error,rate_limit_error,provider_error,server_error.code— Machine-readable identifier (e.g.missing_required_parameter,invalid_api_key,model_not_found,job_not_found).param— Optional. The request field that triggered the error.
HTTP status codes
400 invalid_request_error— Your request was malformed: missing fields, wrong types, unknown model, etc. Fix the request body before retrying.401 authentication_error— Missing or invalid API key. Verify theAuthorization(orx-api-key) header.403 permission_error— Your key is valid but isn't allowed to perform this action. Common causes: requesting a premium model on a free plan (code: "model_requires_higher_plan") or polling a job created by a different key (code: "unauthorized_job_access").404 not_found— The resource doesn't exist. For job polling, this means the job ID is wrong or the job has expired (code: "job_not_found").413 payload_too_large— File or request body exceeds the limit (e.g. 25 MB for audio uploads).429 rate_limit_error— You've hit either your per-minute request limit or your daily token quota. The response includes when the window resets.500 server_error— Internal NavyAI error. Safe to retry with backoff.502 / 503 provider_error— All upstream providers failed for this model. NavyAI already retries internally; if you see this, every provider is down. Retry with backoff or fall back to a different model.
Streaming errors
While a stream is in flight, errors arrive as an SSE data: event with the same JSON error body and then the stream closes. If the first chunk has not been sent yet, you may get a normal HTTP error response instead. Defensive clients should handle both.
Rate limits
Two limits are enforced per API key:
- Daily token quota — Tokens count after the model's
token_multiplier. Resets at 00:00 UTC. - Requests per minute (RPM) — A sliding 60-second window starting from your first request in the window.
When either limit is exceeded, requests return 429 rate_limit_error. Use GET /v1/usage to read the current state and the exact reset time before retrying. Plans differ in both quotas — see your dashboard for the numbers tied to your key.
Retry strategy
- Retry on
429,500,502,503. - Do not retry on
400,401,403,404— fix the request first. - Use exponential backoff with jitter, starting at ~500 ms.
- Respect the reset time from
/v1/usagewhen retrying after a429.
Plan-locked models
Some models require a paid plan. The catalog (GET /v1/models) exposes premium and required_plan on each entry so you can hide locked options in your UI before a user ever sends a request. Calling a locked model returns 403 with code: "model_requires_higher_plan".