Sign in →

Rate Limits

Aforo enforces rate limits to keep the platform stable for every workspace. The dimension a limit is keyed on depends on the surface: authenticated API traffic is limited per workspace (tenant), the headless storefront API per storefront key (consumer), and public/unauthenticated routes per IP.

Default Limits

SurfaceLimitScope
Authenticated API (default)300 req/min · 10,000 req/hrPer workspace
Headless Storefront600 req/minPer storefront key
Public storefront pages120 req/minPer IP
Public KB / docs demo60 req/minPer IP
Auth endpoints30 req/minPer IP
Support / quote submission10 req/minPer IP

The gateway enforces these; the application layer also applies a 300 req/min per-workspace default as a backstop. Limits are not a per-plan entitlement — for per-customer usage caps on your own products, see the subscription-level section below.

Rate Limit Headers

Every API response includes headers showing your current rate limit status:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 213
HeaderWhereDescription
X-RateLimit-LimitApp + gatewayTotal requests allowed in the window
X-RateLimit-RemainingApp + gatewayRequests remaining in the current window
RateLimit-ResetGatewaySeconds until the window resets (gateway routes only)
X-RateLimit-Limit-Minute / -HourGatewayPer-window limits on multi-window gateway routes

The application layer sets only X-RateLimit-Limit and X-RateLimit-Remaining. Gateway-fronted routes add the RateLimit-Reset and per-window (-Minute / -Hour) variants.

429 Too Many Requests

When you exceed the limit, the API returns:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0

{
  "success": false,
  "errors": [
    { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Max 300 requests per minute per tenant." }
  ]
}

The Retry-After header is your reliable signal for backoff. (At the gateway, a rejected request may instead return Kong's own { "message": "API rate limit exceeded" } body — handle both by keying on the 429 status, not the body shape.)

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/batch
Content-Type: application/json

{
  "events": [
    { "customerId": "cust_1", "metricName": "api-calls", "quantity": 1, "occurredAt": "..." },
    { "customerId": "cust_2", "metricName": "api-calls", "quantity": 5, "occurredAt": "..." }
  ]
}

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:

  1. Optimize batching — Use batch ingestion for usage events instead of individual calls
  2. Upgrade plan — Higher Aforo plans include higher rate limits
  3. Contact support — For enterprise-scale requirements, contact your account manager for custom limits

Contact support →