> ## Documentation Index
> Fetch the complete documentation index at: https://docs.r3al.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limiting

> Per-caller sliding-window limits on every /v1/* call, with a tighter tier on login/register.

Every request is rate-limited by an in-memory sliding-window counter -- no external dependency (no Redis, no `slowapi`). Limits are per **caller identity**, not global:

* Authenticated calls are keyed by a hash of the Bearer token (API key, session, or master key).
* Unauthenticated calls (before any credential is known to be valid, e.g. a login attempt) are keyed by source IP.

This means one noisy caller can't exhaust another caller's quota, and an unauthenticated brute-force attempt against `/v1/auth/login` is throttled per-IP even before it ever presents a valid credential.

## Limits

| Tier    | Default          | Env override                   | Applies to                                                             |
| ------- | ---------------- | ------------------------------ | ---------------------------------------------------------------------- |
| General | 120 requests/min | `R3AL_RATE_LIMIT_PER_MIN`      | Every route under `/v1/*` (jobs, keys, alerts, deployments, logs, ...) |
| Auth    | 20 requests/min  | `R3AL_RATE_LIMIT_AUTH_PER_MIN` | `POST /v1/auth/register`, `/login`, `/site-login`                      |

The auth tier is intentionally tighter -- these are the endpoints someone would actually try to brute-force (login) or spam (registration).

## Response when limited

A `429` with a structured body and a standard `Retry-After` header (seconds until the window frees up):

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 37
Content-Type: application/json
```

```json theme={null}
{
  "status": "error",
  "code": "rate_limited",
  "error": "Rate limit exceeded (120 requests/min). Try again in 37s.",
  "request_id": "a1b2c3d4e5f6"
}
```

Same [error envelope](/api/errors) as every other error in this API.

<Warning>
  **Single-process only.** Counters live in this process's memory. If this API ever runs with multiple `uvicorn` workers or multiple replicas behind a load balancer, each process keeps its own counters -- the effective limit multiplies by however many processes are running. Fine for a single-instance deployment (e.g. one Railway service); move to a shared store (Redis) first if you scale horizontally.
</Warning>
