# Rate Limits

Every API key can carry a per-key requests-per-minute (RPM) limit,
configured on the key in the console. The limit is enforced with a
Redis-backed sliding window (a key with no configured limit is
unlimited).

## Headers

The gateway does not emit `X-RateLimit-*` headers. On rejection the
response is:

- HTTP `429 Too Many Requests`
- Body `{"error": {"message": "Rate limit exceeded: N RPM", "type": "rate_limit_exceeded"}}`
- Header `Retry-After: 60` - the worst-case seconds until the sliding
  window has drained enough to accept a new request

That 429 + `Retry-After` pair is the only rate-limit signal on the wire:
there is no remaining-count or reset-timestamp header to read.

## Sliding window

The limiter uses a true sliding window (a Redis sorted set of request
timestamps trimmed to the last 60 seconds), not a fixed bucket that
dumps and refills at minute boundaries. After a 429, each elapsed
second frees capacity proportionally - retrying exactly `Retry-After`
seconds later is always safe, and slow trickle traffic recovers earlier
than a fixed window would allow.

## Recommended client behavior

1. Track your own outbound request rate per key against the key's
   configured RPM - the server gives no advance warning before the 429
2. On 429, wait `Retry-After` (60s) seconds before retrying, or
   whatever is left of it
3. Do not hammer during the window - rejected requests don't consume
   window capacity, but a tight retry loop wastes the whole minute -
   space retries by `Retry-After`
4. After repeated 429s, back off multiplicatively and surface the
   condition to the caller

## Per-key limits

Limits are configured per key in the console (keys with no limit are
unlimited). Different keys have independent quotas - spreading load
across multiple keys is a legitimate way to raise aggregate throughput,
and the fresh key you create during rotation
([`/agents/patterns/key-rotation.md`](/agents/patterns/key-rotation.md))
starts with a clean window.

Note: the limiter fails open if its Redis backend is unreachable - a
gateway blip degrades to no rate limiting rather than false 429s.
