Rate Limits
Aforo enforces rate limits on all API endpoints to ensure platform stability for all tenants. Rate limits are applied per API key, not per IP address.
Default Limits
Rate Limit Headers
Every API response includes headers showing your current rate limit status:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1713362460
X-RateLimit-Window: 60
429 Too Many Requests
When you exceed the limit, the API returns:
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 23
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1713362460
{
"type": "https://errors.aforo.ai/rate-limited",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit of 600 requests per minute exceeded. Retry after 23 seconds.",
"retryAfter": 23
}
Handling 429 in Your Code
Node.js / TypeScript
async function callWithRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn()
} catch (err: any) {
if (err.status === 429 && attempt < maxRetries) {
const retryAfter = parseInt(err.headers?.['retry-after'] ?? '5', 10)
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000))
continue
}
throw err
}
}
throw new Error('Max retries exceeded')
}
Python
import time
import httpx
def call_with_retry(fn, max_retries=3):
for attempt in range(max_retries + 1):
response = fn()
if response.status_code == 429 and attempt < max_retries:
retry_after = int(response.headers.get('retry-after', 5))
time.sleep(retry_after)
continue
response.raise_for_status()
return response
raise Exception("Max retries exceeded")
The official Aforo SDK (@aforo/metering / aforo-metering) handles 429 responses automatically with exponential backoff — you don't need to implement retry logic manually when using the SDK.
Bulk Ingestion
If you need to ingest large volumes of historical data, use the batch endpoint rather than individual events:
POST /v1/ingest/events/batch
Content-Type: application/json
{
"events": [
{ "customerId": "cust_1", "metricId": "api-calls", "quantity": 1, "timestamp": "..." },
{ "customerId": "cust_2", "metricId": "api-calls", "quantity": 5, "timestamp": "..." }
]
}
Batch requests accept up to 1,000 events per call and count as a single request against your rate limit.
For historical data migration (millions of events), use File Upload in the Developer Hub.
Rate Limit Enforcement (Subscription Level)
Separate from API rate limits, Aforo can enforce per-customer usage limits on your API products through rate plans:
- Hard limits (
enforcement: BLOCK) — Reject requests when customer exceeds quota - Soft limits (
enforcement: ALERT) — Allow requests, notify operator
These customer-level limits are enforced at the gateway (Kong, Apigee, etc.) or via the Aforo metering SDK, not at the API level.
Increasing Limits
If the default limits don't meet your needs:
- Optimize batching — Use batch ingestion for usage events instead of individual calls
- Upgrade plan — Higher Aforo plans include higher rate limits
- Contact support — For enterprise-scale requirements, contact your account manager for custom limits