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

# Rate Limits

> Bavlio sets X-RateLimit-Limit and X-RateLimit-Reset headers on API-key authenticated requests. How to read them and how to back off correctly.

Bavlio enforces per-key rate limits on requests authenticated with an API key. The limit varies by plan tier. Headers tell you the current state.

## Headers

| Header              | Description                                                     |
| ------------------- | --------------------------------------------------------------- |
| `X-RateLimit-Limit` | Your current per-window limit (an integer).                     |
| `X-RateLimit-Reset` | Unix epoch seconds at which the current window resets.          |
| `Retry-After`       | Present only on 429 responses. Seconds to wait before retrying. |

<Note>
  **There is no `X-RateLimit-Remaining` header.** Compute remaining requests yourself by tracking your own send count within the current window if you need an in-flight estimate. The headers above are sent on every response (where available).
</Note>

## Caveats

* **API-key auth only.** Requests authenticated with a Supabase JWT (dashboard sessions) do not get rate-limit headers and follow a different limit.
* **Redis-backed.** Rate limiting depends on Redis. If Redis is unavailable, Bavlio fails open: requests proceed, but no headers are set. This is a deliberate tradeoff; reliability beats strict enforcement during infrastructure incidents.
* **Per-key, not per-IP.** Limits are scoped to your API key. Two keys on the same workspace each have their own bucket.

## Example 429 response

```http theme={null}
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Reset: 1746590160
Retry-After: 13
Content-Type: application/json

{
  "detail": "RATE_LIMITED",
  "message": "Too many requests; retry after 13s"
}
```

## Backoff pattern

Honor `Retry-After` exactly on 429. On 5xx, exponential backoff capped at a few attempts.

```python Python theme={null}
import time
import httpx

def call_with_backoff(client, method, path, *, max_retries=5, **kwargs):
    """Retry on 429 and 5xx with exponential backoff."""
    for attempt in range(max_retries):
        response = client.request(method, path, **kwargs)
        if response.status_code < 400:
            return response
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", "1"))
            time.sleep(retry_after)
            continue
        if 500 <= response.status_code < 600:
            time.sleep(2 ** attempt)
            continue
        response.raise_for_status()
    response.raise_for_status()
```

## See also

<CardGroup cols={2}>
  <Card title="Errors & Idempotency" icon="circle-exclamation" href="/errors">
    Full status code taxonomy, retry rules, and current idempotency state.
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Minimal happy-path agent integration.
  </Card>
</CardGroup>
