Documentation

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:

JSON
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 the Authorization (or x-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/usage when retrying after a 429.

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".