# Rate Limits

The Not AI Public REST API applies a sliding-window rate limit at the edge. Limits are scoped to the plan tier of the integration the presented key resolves to. The free tier is included, and the tier only changes the rate of consumption, not the right to consume.

Per-key isolation requires the `Authorization: Bearer` form. The edge counter reads the `Authorization` header value to separate callers, so `x-api-key` requests share a per-tier edge bucket and can throttle each other under load. Use `Authorization: Bearer` for production traffic; reserve `x-api-key` for quick scripts and shell pipelines where the precedence is acceptable.

## Per-tier limits

| Plan | Per-minute | Max page size | Available history window |
|------|------------|---------------|--------------------------|
| Free | 60 | 50 | 7 days (default) |
| Pro | 600 | 100 | 30 days (default) |
| Enterprise | 6,000 | 100 | Up to 7 years |

A request is rejected when the per-minute window for its tier is exhausted. Per-day quotas are not currently enforced at the edge.

The max page size caps the `?pageSize=` query parameter on every list endpoint. Above the tier cap, the server clamps to the cap and reflects the effective value back in `pagination.limit`. The `?pageSize=` you asked for is never larger than what the server is willing to serve. If you need bigger pages, upgrade the integration tier.

Requests that target a `startDate` outside the available history window return an empty page rather than an error.

## Tier echo header

Every response to a successfully authenticated request carries an `x-isnotai-tier` header echoing the resolved plan tier (`free`, `pro`, or `enterprise`), regardless of status code. It is stamped from the integration record, so you can confirm in one request which row of the table above applies to a given key, including on `4xx` validation failures and `5xx` errors that surface after auth.

Responses returned before the integration resolves do not carry the header. In practice that is the `401 Unauthorized` envelope when authentication fails, and the rare `500 INTERNAL_ERROR` returned if the authentication service itself errors before resolving the integration.

```
x-isnotai-tier: pro
```

No live remaining-quota counters are emitted. Pace your traffic against the table above, not against per-response telemetry.

## When you hit the limit

A request that exhausts the per-minute window returns `429 Too Many Requests` with the standard error envelope:

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded for this API key."
  }
}
```

A `Retry-After` header is included when the edge can compute one. Wait at least that long before retrying. If the header is absent, back off with an exponential delay seeded at one second.

```python
import os
import random
import time
import requests

BASE_URL = "https://api.isnotai.com"
HEADERS = {"Authorization": f"Bearer {os.environ['ISNOTAI_API_KEY']}"}

def get_with_throttle(path, params=None, max_attempts=8):
    delay = 1.0
    for attempt in range(max_attempts):
        response = requests.get(f"{BASE_URL}{path}", headers=HEADERS, params=params, timeout=10)
        if response.status_code != 429:
            return response
        retry_after = response.headers.get("Retry-After")
        if retry_after and retry_after.isdigit():
            time.sleep(int(retry_after))
        else:
            time.sleep(delay + random.random())
            delay = min(delay * 2, 60.0)
    response.raise_for_status()
    return response
```

## Staying under the limit

- Pace your traffic against the per-tier table above; the API does not surface live remaining-quota counters.
- For backfills, paginate at a steady cadence rather than fanning out. Two parallel walkers on the same `Authorization: Bearer` key share the same per-minute budget.
- Cache responses on your side when the same data will be reread soon. `/v1/stats`, `/v1/courses`, and `/v1/integration` are particularly cache-friendly.
- If you need a higher ceiling, change the integration's plan in the dashboard at `dash.isnotai.com`. The new tier applies on the next request; there is no in-flight switchover.
