# API Errors

Errors return an OpenAI-style JSON body, plus an `x-should-retry` response header:

```json
{
  "error": {
    "message": "Insufficient credits. Top up at keeprouter.com/console/credits",
    "type": "invalid_request_error",
    "code": "insufficient_credits",
    "retryable": false,
    "doc_url": "https://keeprouter.com/docs/errors#insufficient_credits"
  }
}
```

`retryable` (and the `x-should-retry` header) tells you whether the same request can succeed on retry: `true` means retry after any `Retry-After`; `false` means fix something first.

### invalid_api_key
**401 · not retryable.** The API key is missing, disabled, or expired. Create or re-enable a key in the [console](/console/keys).

### account_suspended
**403 · not retryable.** Your account is suspended. Email **support@keeprouter.com**.

### insufficient_credits
**402 · not retryable as-is.** Your available credits cannot cover this request's maximum estimated cost, or are reserved by requests already in flight. Lower the output-token limit, wait for an in-flight request to finish, or [add credits](/console/credits).

### model_requires_topup
**403 · not retryable.** Without a top-up only the published free models are callable. Top up to call this model, or choose one of those.

### model_not_allowed
**403 · not retryable.** This API key's model allowlist doesn't include the requested model. Edit the key's allowlist in the [console](/console/keys).

### invalid_max_tokens
**400 · not retryable as-is.** The request's output-token limit must be a finite positive integer. Correct `max_tokens`, `max_completion_tokens`, or `max_output_tokens` (whichever the endpoint uses) before retrying.

### invalid_stream
**400 · not retryable as-is.** `stream` must be the JSON boolean `true` or `false`, not a string or number. Correct the field before retrying.

### invalid_n
**400 · not retryable as-is.** Chat Completions and image generation accept `n` only when it is exactly `1`. Send separate requests for multiple outputs so each result is admitted and billed independently.

### invalid_model
**400 · not retryable as-is.** `model` must be a string from 1 to 256 characters with no whitespace. Copy an exact model ID from the current [model catalog](/models) or `GET /v1/models`, then retry.

### model_not_available
**403 · not retryable as-is.** The requested model has no route candidate available to this API key. Confirm the model ID, endpoint compatibility, and key allowlist against the current [model catalog](/models), or choose another compatible model.

### request_body_too_large
**413 · not retryable as-is.** The JSON request body exceeds the **2 MiB** gateway limit. Reduce or split the request before trying again. This limit also applies to chunked bodies without a `Content-Length` header and to `/v1/messages/count_tokens`.

### pricing_unavailable
**503 · not retryable as-is.** KeepRouter does not have a complete published price for this model's current route candidates, so the request is stopped before any upstream call or charge. Choose another model or email **support@keeprouter.com**.

### key_limit_reached
**429 · retryable after the window or an in-flight request finishes.** This request's maximum estimated cost, together with committed and reserved spend, would cross the key's daily or monthly limit. Lower the output-token limit, wait for a reservation to release, raise the key limit, or wait for the period to reset.

### concurrency_limit_exceeded
**429 · retryable.** This account has too many in-flight requests (or its smaller high-cost request pool is full). Wait for one to finish, then retry after `Retry-After` (currently 5 seconds).

### rate_limit_exceeded
**429 · retryable.** You exceeded the requests-per-minute limit for your tier. Back off and retry after `Retry-After`. Topped-up accounts get higher limits.
