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:
{
"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.
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: Bearerkey 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/integrationare 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.