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

# Rate limits

> Per-second request limits, response headers, and how to handle `429` correctly.

AcreLens uses a **sliding window** rate limit applied per API key. Cross the threshold and you get `429 rate_limit_exceeded` with a `Retry-After` header telling you when to try again.

## Limits per tier

Rate limits scale with your tier. The limit is expressed **per second** but enforced over a sliding \~10-second window — so the actual budget is `rate × window` requests in any 10-second span (e.g. DEVELOPER = 5/s × 10s = 50 requests per window).

| Tier | Requests per second | Per-window budget (\~10s) |
| - | - | - |
| DEVELOPER | 5 | 50 |
| STARTER | 10 | 100 |
| GROWTH | 20 | 200 |
| SCALE | 50 | 500 |
| ENTERPRISE | 100 | 1,000 |

| | Value |
| - | - |
| Window | Sliding \~10 seconds |
| Granularity | Per API key (each key has its own bucket) |

If you have multiple keys, each gets its own per-tier budget.

> Higher limits (up to 100 req/sec) are available for enterprise contracts. Email [support@acrelens.com](mailto:support@acrelens.com).

## Response headers

Every response — success or failure — includes:

| Header | Example | Meaning |
| - | - | - |
| `X-RateLimit-Limit` | `50` | Requests allowed in the current window — the **windowed budget** (rate/s × window seconds), not the per-second number. A DEVELOPER key (5/s over a 10s window) reports `50` here. |
| `X-RateLimit-Remaining` | `49` | Requests left in this window |
| `X-RateLimit-Reset` | `1714147200` | Unix timestamp (seconds) when this window resets |

When you exceed the limit, the response also includes:

| Header | Example | Meaning |
| - | - | - |
| `Retry-After` | `2` | Seconds to wait before retrying |

## `429` response shape

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 2 seconds.",
    "request_id": "req_01HY2Z...",
    "retriable": false,
    "docs_url": "https://docs.acrelens.com/errors/rate_limit_exceeded"
  }
}
```

Note `retriable: false`. This is intentional — the error itself isn't transient, it's telling you to slow down. *Treat it as retriable in your client logic*, but always wait the `Retry-After` interval first.

## Handling `429` correctly

The right pattern is **respect `Retry-After`, then exponential backoff if you keep hitting it**:

```javascript theme={null}
async function fetchWithBackoff(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, options);

    if (res.status !== 429) return res;

    // Wait the server-suggested interval first
    const retryAfter = parseInt(res.headers.get("Retry-After") ?? "1", 10);
    // Add jitter and exponential backoff for repeat 429s
    const delay = retryAfter * 1000 + 2 ** attempt * 1000 + Math.random() * 500;
    await new Promise(r => setTimeout(r, delay));
  }
  throw new Error("Rate limit retries exhausted");
}
```

Common mistakes:

* **Retrying immediately.** `Retry-After: 2` means wait at least 2 seconds. Hammering the endpoint just keeps you locked out.
* **Ignoring `X-RateLimit-Remaining`.** If you read `1` from a recent response, slow down *before* the 429 — back off pre-emptively.
* **Not jittering.** If multiple workers all retry at exactly `now + Retry-After`, you'll thunder back into the limit.

## Polling vs. webhooks

If you're hitting `429`s while polling for report completion, switch to [webhooks](/guides/webhooks). One webhook delivery costs zero rate-limit budget; a polling loop checking every 5 seconds for 90 seconds spends \~18 requests. With concurrent reports it adds up fast.

## Quota vs. rate limits

These are different limits with different errors:

| | Rate limit | Quota / spend |
| - | - | - |
| Code | `rate_limit_exceeded` | `quota_exceeded`, `insufficient_balance`, `DAILY_CAP_EXCEEDED`, `MONTHLY_CAP_EXCEEDED` |
| HTTP | 429 | 402, 429 |
| Trigger | Too many requests per second | Out of money / out of allowance |
| Recovery | Wait `Retry-After` seconds | Top up balance, contact billing |

See the [errors reference](/reference/errors) for the full catalog.

## Health checks

`GET /v1/health` is **unauthenticated and not rate-limited** — safe to use for liveness probes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.