Rate Limits
ARQERA enforces two layers of rate limiting: request-level (per-endpoint throttling) and usage-level (monthly allowances tied to your subscription tier).
Request Rate Limits
Request rate limits protect API stability. They apply to all tiers equally.
| Category | Limit | Window | Endpoints |
|---|---|---|---|
| Global | 1,000 requests | 1 hour | All endpoints |
| Auth | 10 requests | 1 minute | /auth/login, /auth/register, /auth/password, /auth/oauth, /auth/sso |
| AI / Ara | 100 requests | 1 minute | /ai/*, /ara/*, /composer/* |
| Search | 60 requests | 1 minute | Any endpoint containing /search |
| Export | 30 requests | 1 minute | Any endpoint containing /export |
| Billing | 30 requests | 1 minute | /billing/* |
Exempt Endpoints
These endpoints are excluded from category-specific limits (global limit still applies):
/auth/me— called on every page load/auth/csrf— CSRF token retrieval
Rate Limit Response Headers
Every API response includes rate limit headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997
X-RateLimit-Reset: 1708531200
X-RateLimit-Category: global
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests remaining before the limit is reached |
X-RateLimit-Reset | Unix timestamp when the rate limit window resets |
X-RateLimit-Category | Which rate limit category was applied (e.g., global, auth, ai) |
Usage Limit Headers (on 429 responses)
When a usage limit is exceeded, the 429 response includes additional headers:
X-Usage-Limit: 1000
X-Usage-Current: 1001
X-Usage-Type: api_calls
Retry-After: 3600
| Header | Description |
|---|---|
X-Usage-Limit | Your monthly allowance for this resource (or unlimited) |
X-Usage-Current | Your current usage count |
X-Usage-Type | Resource type: tokens, api_calls, storage, users |
Retry-After | Seconds until the rate limit window resets |
Handling Rate Limits (429 Responses)
When you exceed a rate limit, the API returns HTTP 429 with a JSON body:
{
"detail": "API call limit exceeded. Please upgrade your plan or wait until next billing period."
}
Recommended Client Behavior
- Read the
Retry-Afterheader and wait that many seconds before retrying - Implement exponential backoff for repeated 429s
- Monitor
X-RateLimit-Remainingproactively to avoid hitting limits - Cache responses where possible to reduce API calls
- Use webhooks instead of polling for real-time updates
Example: Retry with Backoff
Python
import time
import requests
def call_with_retry(url, headers, payload, max_retries=3):
for attempt in range(max_retries):
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
wait = min(retry_after, 2 ** attempt * 10)
print(f"Rate limited. Waiting {wait}s before retry...")
time.sleep(wait)
continue
return response
raise Exception("Max retries exceeded")
TypeScript
async function callWithRetry(url: string, options: RequestInit, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "60");
const wait = Math.min(retryAfter, Math.pow(2, attempt) * 10) * 1000;
console.log(`Rate limited. Waiting ${wait}ms...`);
await new Promise(resolve => setTimeout(resolve, wait));
continue;
}
return response;
}
throw new Error("Max retries exceeded");
}
API Key Rotation
All API keys expire after 90 days by default (3-month rotation cycle). You receive a notification 24 hours before deactivation. Enterprise customers can request non-expiring keys.