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/statusis lightweight, but donβt poll it in a tight loop - Handle 429s gracefully β always implement retry logic in production code