# Rate limits

URL: https://docs.router.ezat.io/reference/rate-limits

> The per-key requests-per-minute limit, per-key spend limits, the organization balance, capacity limits, the headers that come back, and how to back off and retry.

## When to use this page

You got a 429, 402, 529 or 503, or you are building a client that should retry well. Every error type is on [Errors](https://docs.router.ezat.io/reference/errors.md).

## The limits

| Limit | Applies to | Default | When it is reached |
| --- | --- | --- | --- |
| Requests per minute | Each API key | 1,000 | 429 `rate_limit_error`, `retry-after: 30` |
| Spend limit | Each API key, if you set one | None | 402 `billing_error` |
| Balance | The organization | | 402 `billing_error` when the balance is zero or below |
| Capacity | Each model | | 529 `overloaded_error` (503 on the OpenAI-compatible API), `retry-after: 5`; or 429 `rate_limit_error`, `retry-after: 10` |

On the OpenAI-compatible API, the same limits return the OpenAI format: 429 `rate_limit_exceeded`, 402 `insufficient_quota`, and 503 `overloaded`.

## Requests per minute

- Each key can make 1,000 requests per minute unless EZAT Router has set another limit for it. Keys don't share this limit.
- `POST /v1/messages`, `POST /v1/messages/count_tokens` and `POST /openai/v1/chat/completions` count. Model lists don't.
- The count resets at the start of each minute. Refused requests count too, so retrying in a tight loop keeps the key over the limit until the minute ends.
- Over the limit, the gateway answers 429 with `retry-after: 30` and the message "This API key exceeded its requests-per-minute limit". The request isn't charged.

The dashboard can't change a key's limit. To ask for a different one, email support@ezat.io with the key's name and the start of the key as the dashboard shows it (`ezat_sk_…`).

## Spend limits

A spend limit caps what one key can spend in a period. Set it when you create the key: **API keys** → **Create key** → **Spend limit**, with an **Amount (USD)** and a **Period**.

| Period | Resets |
| --- | --- |
| day | At 00:00 UTC |
| month | On the 1st of the month, 00:00 UTC |
| total | Never: it covers everything the key ever spends |

- The gateway checks the limit before each request. Once the key's spending in the period reaches the limit, requests get 402 with a message such as "This API key reached its monthly spend limit of …".
- A request that starts under the limit finishes, so spending can end slightly above it.
- The dashboard can't change a key's limit after it is created. Create a new key with the limit you want, move your app to it, then revoke the old key.

See [API keys](https://docs.router.ezat.io/api-keys.md) for the rest of a key's settings.

## Organization balance

All keys in an organization spend one prepaid balance. When it is zero or below, every key gets 402 until someone adds credit. See [How billing works](https://docs.router.ezat.io/billing.md).

## Capacity

Each model is served through one or more provider deployments. The gateway picks one for each request and, if it fails before the response starts, tries up to two others.

- When none can take the request, the gateway answers 529 `overloaded_error` with `retry-after: 5` (503 `overloaded` on the OpenAI-compatible API).
- When the providers are rate limiting, it answers 429 "Rate limited upstream. Please retry shortly." with `retry-after: 10`.
- Neither is charged. Retry after `retry-after`.

A model that has no capacity at all shows `"available": false` in `GET https://api.router.ezat.io/api/models`. See [Models](https://docs.router.ezat.io/models.md).

## Headers

| Header | On | Value |
| --- | --- | --- |
| `retry-after` | 429, 529 and 503 | Seconds to wait before retrying |
| `request-id` | Requests that reached a model | The request's id in Usage |
| `x-request-id` | Every response | An id for the HTTP call |

There are no headers with your remaining quota (no `x-ratelimit-*` or `anthropic-ratelimit-*`).

## Retrying

The official Anthropic and OpenAI SDKs (Python and Node.js) already retry connection errors, 408, 409, 429 and every 5xx (529 and 503 included), twice by default, with exponential backoff, and they wait the `retry-after` time when the header is there. Change it with `max_retries` (Python) or `maxRetries` (Node.js), on the client or per request.

If you write your own client:

1. Retry only 429, 500, 529 and 503, and connection errors. Don't retry 400, 401, 402, 403, 404 or 413.
2. Wait `retry-after` seconds when the header is there.
3. Otherwise wait exponentially longer each time, with random jitter: for example 0.5 s, 1 s, 2 s, 4 s, up to about 8 s, each multiplied by a random factor between 0.75 and 1.
4. Stop after a few attempts and report the error with its `request-id` and `x-request-id`.
5. Send the retry exactly as before, with the same `x-ezat-session` header (or `prompt_cache_key` on the OpenAI-compatible API) if you use one. The gateway keeps a conversation on the provider that holds its prompt cache, so an identical retry keeps the cache and costs less.

Don't retry a 504 `timeout_error` as it is: it means a non-streaming request ran for 590 seconds, and the SDKs would send it again in full. Send long requests with `"stream": true` instead.

```python title="Backoff without an SDK"
import random
import time


def with_retries(send, attempts=5):
    """send() returns (status, headers, body). Retries 429, 500, 503 and 529."""
    for attempt in range(attempts):
        status, headers, body = send()
        if status not in (429, 500, 503, 529) or attempt == attempts - 1:
            return status, headers, body
        retry_after = headers.get("retry-after")
        if retry_after:
            delay = float(retry_after)
        else:
            delay = min(0.5 * 2**attempt, 8) * random.uniform(0.75, 1.0)
        time.sleep(delay)
```

## For AI agents

1. Per-key limit: 1,000 requests per minute by default; 429 with `retry-after: 30` when over it.
2. On 429, 529 or 503, wait `retry-after` seconds, then retry with exponential backoff and jitter. The official SDKs do this already (2 retries by default; raise `max_retries` / `maxRetries` for batch jobs).
3. On 402, stop: the balance is used up or the key reached its spend limit. Tell the user to add credit at https://router.ezat.io/billing, or to create a key with a higher limit.
4. There are no remaining-quota headers. Pace requests yourself if you need to stay under the per-minute limit.
5. Keep the same `x-ezat-session` value (or `prompt_cache_key`) when retrying, so prompt caching keeps working.
6. Use `"stream": true` for long requests: non-streaming requests end with a 504 after 590 seconds.