Public-API budgets
Per key, per minute (configurable at key creation)
| Field | Type | Notes |
|---|---|---|
default | 60 req/min | Applied to every new key unless you specify rate_limit_per_min at creation. |
minimum | 1 req/min | Lower bound enforced server-side. |
maximum | 600 req/min | Upper bound enforced server-side. Need more? Email us. |
Limits are scoped per api_key_id. Multiple keys belonging to the same user get independent budgets. Hitting the budget returns 429 with Retry-After.
Dashboard endpoint budgets
Per user, on key-management routes
| Field | Type | Notes |
|---|---|---|
POST /api/api-keys | 5 / hour | Create a new key. |
GET /api/api-keys | 30 / min | List your keys. |
DELETE /api/api-keys/[id] | 30 / min | Revoke a key. |
GET /api/api-keys/[id]/usage | 30 / min | Per-key usage rollup. |
Response headers
On every gateway response you'll find:
Headers
| Field | Type | Notes |
|---|---|---|
X-RateLimit-Limit | integer | Your per-key per-minute ceiling. |
X-RateLimit-Remaining | integer | Calls left in the current window. |
X-RateLimit-Reset | unix seconds | When the window resets. |
Retry-After | seconds | Sent on 429 only. Wait at least this long before retrying. |
# A 429 response carries Retry-After + the standard
# X-RateLimit-* headers. Honour Retry-After before retrying.
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1761350400
Content-Type: application/json
{ "error": "Too many requests", "message": "Rate limit exceeded. Please retry shortly." }async function callWithBackoff(url, init, attempt = 0) {
const res = await fetch(url, init);
if (res.status !== 429) return res;
const retryAfter = parseInt(res.headers.get("Retry-After") || "1", 10);
const wait = Math.max(retryAfter, Math.pow(2, attempt)) * 1000;
await new Promise((r) => setTimeout(r, wait));
return callWithBackoff(url, init, attempt + 1);
}import time, requests
def call_with_backoff(method, url, **kw):
for attempt in range(6):
r = requests.request(method, url, **kw)
if r.status_code != 429:
return r
wait = max(int(r.headers.get("Retry-After", "1")), 2 ** attempt)
time.sleep(wait)
r.raise_for_status()