Back to Docs

Rate Limits

Rate limits protect the API infrastructure and ensure fair usage across all clients. Limits vary by environment and subscription tier.

Reading time: 4 minLast updated: Feb 2026

Limits by Environment

Sandbox

Requests per minute60
Requests per day1,000
Monthly limitNo limit
Burst allowance10 req/sec
Concurrent connections5

Production

Requests per minute300
Requests per day50,000
Monthly limitBased on credit balance
Burst allowance50 req/sec
Concurrent connections25

Rate Limit Headers

Every API response includes rate limit headers so you can track your remaining quota in real time.

X-RateLimit-Limit60

Maximum requests allowed in the current window

X-RateLimit-Remaining42

Requests remaining in the current window

X-RateLimit-Reset1740268800

UTC epoch seconds when the window resets

Retry-After12

Seconds to wait before retrying (only on 429 responses)

response-headers.txt
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1740268800

{
  "success": true,
  "data": { ... }
}

Handling 429 Too Many Requests

When you exceed the rate limit, the API returns a 429 status with a Retry-After header indicating how many seconds to wait.

429-response.txt
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1740268812

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Try again in 12 seconds.",
    "retryAfter": 12
  }
}

Retry Strategies

Implement exponential backoff with jitter for resilient integrations.

retry.ts
async function withRetry(fn, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (err.status !== 429 || attempt === maxRetries) throw err;

      const retryAfter = err.headers?.["retry-after"] || 1;
      const jitter = Math.random() * 1000;
      const delay = retryAfter * 1000 + jitter;

      console.log(`Rate limited. Retrying in ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}
retry.py
import time, random

def with_retry(fn, max_retries=3):
    for attempt in range(max_retries + 1):
        try:
            return fn()
        except ApiError as e:
            if e.status != 429 or attempt == max_retries:
                raise

            retry_after = int(e.headers.get("retry-after", 1))
            jitter = random.uniform(0, 1)
            delay = retry_after + jitter

            print(f"Rate limited. Retrying in {delay:.1f}s...")
            time.sleep(delay)

Respect the Retry-After header

Always wait at least the number of seconds specified in the Retry-After header before retrying.

Add jitter to prevent thundering herd

Add a random delay (0–1s) to your retry timing to prevent multiple clients from retrying simultaneously.

Use exponential backoff for transient errors

For 500/503 errors, double the wait time on each retry: 1s → 2s → 4s → 8s (with jitter).

Set a maximum retry count

Cap retries at 3–5 attempts. If the request still fails, log the error and alert your team.

Need Higher Limits?

Enterprise customers can request custom rate limits. Contact support@compliancegrid.ai with your use case and expected request volume.

Error Codes

HTTP status codes and error format

Authentication

API keys and OAuth 2.0