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

# Rate limits

> How request quotas work, how to read the rate limit headers, and how to back off when you hit a 429

Every request is checked against two windows: a per-minute limit and a per-day limit. A request must fit both. Quotas are tracked per API surface, per workspace, so heavy list traffic never starves your campaign calls, and one teammate's script draws from the same pool as yours.

## Quotas by surface

| Surface                    | Endpoints                                          | Per minute | Per day |
| -------------------------- | -------------------------------------------------- | ---------- | ------- |
| Lists & exports            | `/business/lists*`, `/business/exports*`           | 120        | 10,000  |
| Campaigns & knowledge hubs | `/business/campaigns*`, `/business/knowledge-hubs` | 30         | 1,000   |
| Account                    | `/business/me`, `/business/credits`                | 120        | 10,000  |
| Prospect search            | `/business/prospects/search*`                      | 20         | 1,000   |
| Saved searches             | `/business/saved-searches*`                        | 60         | 5,000   |

<Note>
  Prospect search is also gated by [credits](/concepts/credits). In practice your credit balance bounds search throughput before the rate limit does, so budget credits first and treat the 20/minute ceiling as a burst cap.
</Note>

## Reading the headers

Every response — success or 429 — carries three headers:

| Header                | Meaning                                  |
| --------------------- | ---------------------------------------- |
| `RateLimit-Limit`     | Quota of the binding window              |
| `RateLimit-Remaining` | Requests remaining in the binding window |
| `RateLimit-Reset`     | Seconds until the binding window resets  |

The binding window is whichever of the two windows has fewer remaining requests — the one that will stop you first. If both have the same number remaining, the headers bind to whichever resets later. This is why `RateLimit-Limit` can appear to jump between values like 120 and 10,000 across consecutive responses: you are seeing the minute window and the day window trade places as the tighter constraint.

You can watch the headers on any call:

```bash theme={null}
curl -i https://api.tryfuse.ai/api/v1/business/me \
  -u "af_YOUR_KEY:"
```

```text theme={null}
HTTP/2 200
RateLimit-Limit: 120
RateLimit-Remaining: 87
RateLimit-Reset: 22
```

## Handling 429s

When you exceed a limit, the API returns `429` with the standard [error envelope](/concepts/errors) and a `Retry-After` header giving the seconds to wait:

```json theme={null}
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests. Retry after the interval in the Retry-After header.",
    "param": null,
    "doc_url": "https://docs.fuseai.com/concepts/errors#rate_limited",
    "request_id": "req_8fK2mQ4x"
  }
}
```

Honor `Retry-After`. When both windows are exhausted at once, it reflects the window that resets last, so sleeping for `Retry-After` seconds is always sufficient — you will never wake up still rate limited by the other window.

A minimal backoff pattern:

```python theme={null}
import time
import requests

def request_with_backoff(method, url, **kwargs):
    while True:
        response = requests.request(
            method, url, auth=("af_YOUR_KEY", ""), **kwargs
        )
        if response.status_code != 429:
            return response
        time.sleep(int(response.headers["Retry-After"]))

response = request_with_backoff(
    "GET", "https://api.tryfuse.ai/api/v1/business/lists"
)
```

For long-running jobs, it is cheaper to avoid the 429 entirely: check `RateLimit-Remaining` as you go and pause for `RateLimit-Reset` seconds when it approaches zero.

<Warning>
  A `500` is never a quota signal. If the rate limiter itself fails, you get `500 UNEXPECTED_ERROR`, not a 429 — retry it like any other server error rather than treating it as exhaustion. See [Errors](/concepts/errors).
</Warning>

## Staying under the limits

* Batch where the API lets you. Building a list from a saved search moves rows server-side in one call instead of paging results through prospect search — see [Build a list from search](/guides/build-a-list-from-search).
* Use [pagination](/concepts/pagination) cursors at the largest page size that fits your processing, rather than many small pages.
* Exports are asynchronous by design: one call starts the job, and polling the job status is far cheaper against your quota than re-fetching list contents — see [Export a list](/guides/export-a-list).
