# Rate limits

Adspy API · https://www.adspy.sh/docs/api/rate-limits · Updated October 24, 2026

Limits are set in your Enterprise contract and announced on every answer.

## Your limits

| Limit | Default | When reached |
| --- | --- | --- |
| Requests per minute, per key | 300 | 429 rate_limited until the minute ends |
| Research reads per minute, per organization, shared by its keys and MCP connections | 120, or the per-key rate when that is higher (300) | 429 rate_limited until the minute ends |
| New collections per month, per organization (POST /v1/fetches and POST /v1/social/fetches for a brand or account Adspy does not have) | 200 | 429 fetch_quota_exceeded until the first day of next month (UTC) |
| Request body | 4 MB | 413 payload_too_large |
| Query string | 8 KB | 413 payload_too_large |

Your contract can set other values. GET /v1/usage returns the ones that apply and this month's new collections.

Every request also runs one or more research reads, and those count toward your organization's research limit: 120 reads a minute per organization, or your contract's per-key rate when that is higher, shared by all its keys and its MCP connections. Most requests make one read; GET /v1/brands/{brand_key} makes up to seven. So several busy keys, or one key sending many brand requests, can reach it before the key's own limit. Past it, Adspy answers 429 rate_limited with Retry-After.

The monthly quota counts the new collections your organization starts, from its API keys and from its MCP connections, and starts again on the first day of each month (UTC). A brand or account Adspy already has, or one your organization is already collecting, never counts and the quota never refuses it, even once it is used up: its fetch answers state existing, or the running collection's job. Requests sent at the same moment are counted one after the other, so together they never pass the quota. Past it, new collections answer 429 fetch_quota_exceeded with Retry-After.

## Headers

Response headers:

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
X-Request-Id: 5d2e8f14-7c3a-4b96-a0e1-9f6b2c4d8e70
RateLimit-Limit: 300
RateLimit-Remaining: 297
RateLimit-Reset: 41
RateLimit-Policy: 300;w=60
```

| Header | Meaning |
| --- | --- |
| RateLimit-Limit | Requests allowed per window for this key. |
| RateLimit-Remaining | Requests left in the current window. |
| RateLimit-Reset | Seconds until the window resets. |
| RateLimit-Policy | The policy: limit;w=window in seconds. |
| Retry-After | On 429 and 503 answers, and while an idempotent request is still running: seconds to wait. |

## Retrying

Retry 429 and 503 answers after Retry-After, and 500 or network errors with a growing delay. Keep the same Idempotency-Key when you retry a POST.

```sh
# curl retries 429 and 503 answers itself and honours Retry-After
curl --retry 5 "https://www.adspy.sh/api/v1/usage" \
  -H "Authorization: Bearer $ADSPY_API_KEY"
```

```js
async function adspy(path, init = {}, attempts = 5) {
  for (let attempt = 1; ; attempt++) {
    const response = await fetch(`https://www.adspy.sh/api/v1${path}`, {
      ...init,
      headers: {
        Authorization: `Bearer ${process.env.ADSPY_API_KEY}`,
        ...init.headers,
      },
    });
    const retryable = response.status === 429 || response.status === 503;
    if (!retryable || attempt === attempts) return response;
    const wait = Number(response.headers.get("Retry-After") ?? 1);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
  }
}
```

```python
import time

def adspy(method, path, attempts=5, **kwargs):
    headers = {"Authorization": f"Bearer {os.environ['ADSPY_API_KEY']}"}
    headers.update(kwargs.pop("headers", {}))
    for attempt in range(1, attempts + 1):
        response = requests.request(
            method, f"https://www.adspy.sh/api/v1{path}", headers=headers, timeout=70, **kwargs
        )
        if response.status_code not in (429, 503) or attempt == attempts:
            return response
        time.sleep(int(response.headers.get("Retry-After", "1")))
```

## Reading the library

The API is for your own research and products, not for copying the library. Reads have no daily cap: Adspy watches the new records each organization reads in a day and contacts you when they pass your contract's threshold.