Documentation

Rate Limits

Understand OrbitKit API rate limiting tiers, detection, and retry strategies.

The OrbitKit API enforces rate limits to ensure fair usage and protect service stability. Limits are applied per-user based on your account.

Rate limit tiers

Scope Limit Window
General API 300 requests per minute
App creation 5 requests per hour
API key creation 5 requests per hour
Icon upload 10 requests per hour
Domain operations 5 requests per hour
Deploy 10 requests per hour
Preview 20 requests per hour
Export 3 requests per hour
Well-known file upload 5 requests per hour

How rate limiting works

  • Limits are tracked per user (identified by your account)
  • Each endpoint category has its own independent counter
  • Counters reset at the start of each window (minute or hour)
  • The general API limit applies to all endpoints; category-specific limits are additional constraints

Response headers

Every response includes IETF-standard rate limit headers (draft-ietf-httpapi-ratelimit-headers) so you can proactively manage your request rate:

RateLimit-Policy: "default";q=300;w=60
RateLimit: "default";r=295;t=45
Header Description
RateLimit-Policy Quota policy: q = quota limit, w = window in seconds
RateLimit Current state: r = remaining requests, t = seconds until reset
Retry-After Seconds to wait (only on 429 responses)

Detecting rate limits

When you exceed a rate limit, the API returns:

HTTP/1.1 429 Too Many Requests
RateLimit-Policy: "default";q=300;w=60
RateLimit: "default";r=0;t=45
Retry-After: 45
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests",
    "docUrl": "https://orbitkit.io/api/rate-limits/#rate-limited"
  }
}

The Retry-After header indicates how many seconds to wait before retrying.

Retry strategy

Use exponential backoff with jitter to handle rate limits gracefully:

async function requestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) return response;

    const retryAfter = response.headers.get('Retry-After');
    const baseDelay = retryAfter ? parseInt(retryAfter) * 1000 : 1000 * Math.pow(2, attempt);
    const jitter = Math.random() * 1000;

    await new Promise(resolve => setTimeout(resolve, baseDelay + jitter));
  }

  throw new Error('Max retries exceeded');
}

Best practices

  • Cache responses where possible to avoid unnecessary requests
  • Batch operations β€” create your app, configure it fully, then deploy once (rather than deploying after each change)
  • Use status endpoints sparingly β€” GET /api/status is lightweight, but don’t poll it in a tight loop
  • Handle 429s gracefully β€” always implement retry logic in production code