English
API Reference
Rate Limits

Rate Limits

API request limits and how to handle them.

Overview

Rate limits protect the API from abuse and ensure fair usage. Limits are applied per API key and per IP address.

Default Limits

ScopeLimitWindow
Global (per key)100 requests1 minute
Per endpoint20 requests1 minute
Bulk operations10 requests1 minute

Rate Limit Headers

Every response includes rate limit information:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1706000000
HeaderDescription
X-RateLimit-LimitMaximum requests allowed
X-RateLimit-RemainingRequests remaining in window
X-RateLimit-ResetUnix timestamp when limit resets

Exceeded Response

When rate limited, you'll receive:

HTTP/1.1 429 Too Many Requests
Retry-After: 45
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests",
    "details": {
      "limit": 100,
      "window": "60s",
      "retryAfter": 45
    }
  }
}

Handling Rate Limits

Check Headers

const response = await fetch('/api/v1/components', {
  headers: { 'Authorization': 'Bearer sk_live_xxx' }
});
 
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
const resetTime = parseInt(response.headers.get('X-RateLimit-Reset'));
 
if (remaining < 10) {
  console.warn(`Only ${remaining} requests left, resets at ${new Date(resetTime * 1000)}`);
}

Retry Logic

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
 
    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
      console.log(`Rate limited, waiting ${retryAfter}s`);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }
 
    return response;
  }
 
  throw new Error('Max retries exceeded');
}

Best Practices

1. Use Exponential Backoff

const delays = [1000, 2000, 4000, 8000]; // ms
 
async function requestWithBackoff(fn) {
  for (let attempt = 0; attempt < delays.length; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status !== 429) throw error;
      await new Promise(r => setTimeout(r, delays[attempt]));
    }
  }
  throw new Error('Rate limit exceeded after retries');
}

2. Batch Requests

Instead of multiple individual requests:

// Bad: 10 separate requests
for (const id of componentIds) {
  await fetch(`/api/v1/components/${id}`);
}
 
// Good: Use list endpoint with filter
await fetch(`/api/v1/components?ids=${componentIds.join(',')}`);

3. Cache Responses

const cache = new Map();
const TTL = 60000; // 1 minute
 
async function getCached(url) {
  const cached = cache.get(url);
  if (cached && Date.now() - cached.timestamp < TTL) {
    return cached.data;
  }
 
  const response = await fetch(url);
  const data = await response.json();
  cache.set(url, { data, timestamp: Date.now() });
  return data;
}

4. Monitor Usage

let requestCount = 0;
 
function trackRequest() {
  requestCount++;
  if (requestCount % 50 === 0) {
    console.log(`Made ${requestCount} requests this session`);
  }
}

Endpoint-Specific Limits

Some endpoints have stricter limits:

EndpointLimitNotes
POST /incidents10/minIncident creation
POST /subscribers/import5/minBulk import
POST /components/{id}/check60/hourManual health checks
GET /public/*1000/minPublic endpoints

Bulk Operations

For bulk updates, use dedicated bulk endpoints when available:

# Instead of 100 individual updates:
POST /api/v1/components/bulk
{
  "updates": [
    { "id": "comp_1", "status": "operational" },
    { "id": "comp_2", "status": "operational" }
  ]
}

Webhook Rate Limiting

Outgoing webhooks are also rate limited:

TypeLimit
Per subscriber10/min
Per organization100/min

Public API Limits

Public endpoints have higher limits but stricter abuse prevention:

EndpointLimit
/public/status/{slug}1000/min
/public/status/{slug}/incidents1000/min
/public/status/{slug}/feed100/min

Increasing Limits

For higher rate limits:

  1. Contact support with your use case
  2. Implement caching on your end
  3. Use webhooks instead of polling

Monitoring

Track rate limit usage in your application:

class RateLimitMonitor {
  constructor() {
    this.limits = new Map();
  }
 
  update(endpoint, headers) {
    this.limits.set(endpoint, {
      limit: parseInt(headers.get('X-RateLimit-Limit')),
      remaining: parseInt(headers.get('X-RateLimit-Remaining')),
      reset: parseInt(headers.get('X-RateLimit-Reset'))
    });
  }
 
  getStatus() {
    return Object.fromEntries(this.limits);
  }
 
  isNearLimit(endpoint, threshold = 0.1) {
    const info = this.limits.get(endpoint);
    if (!info) return false;
    return info.remaining / info.limit < threshold;
  }
}