Rate Limits
Rate limits protect the API and ensure fair usage across all developers. The Circadify API enforces two types of limits: hourly request rate limits and monthly scan quotas.
Rate Limits by Plan
Section titled “Rate Limits by Plan”Rate limits apply per developer account on a sliding 1-hour window:
| Plan | Requests per Hour | Monthly Scans | Max API Keys |
|---|---|---|---|
| Starter | 300 | 500 | 3 |
| Pro | 1,000 | 5,000 | 5 |
| Enterprise | 5,000 | 50,000 | 10 |
Requests per hour limits apply to all API calls (session start, upload-complete, result retrieval). Monthly scans are consumed only when a new session is created via POST /sdk/session/start.
Rate Limit Headers
Section titled “Rate Limit Headers”Every API response includes headers showing your current rate limit status:
X-RateLimit-Limit: 300X-RateLimit-Remaining: 297X-RateLimit-Reset: 1712005400| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per hour |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the rate limit window resets |
Usage Quota Headers
Section titled “Usage Quota Headers”Session creation responses also include monthly usage headers:
X-Usage-Current: 42X-Usage-Limit: 500X-Usage-Remaining: 458| Header | Description |
|---|---|
X-Usage-Current | Scans used this month |
X-Usage-Limit | Monthly scan limit for your plan |
X-Usage-Remaining | Scans remaining this month |
Handling Rate Limits
Section titled “Handling Rate Limits”When you exceed the rate limit, the API returns a 429 response with a Retry-After header:
{ "error": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded", "retryable": true}Response headers on 429:
Retry-After: 45X-RateLimit-Limit: 300X-RateLimit-Remaining: 0X-RateLimit-Reset: 1712005400Always respect the Retry-After header — it tells you how many seconds to wait before retrying:
async function callWithRateLimit(url: string, options: RequestInit) { const response = await fetch(url, options);
if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10); console.log(`Rate limited. Retrying in ${retryAfter} seconds.`); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); return fetch(url, options); }
return response;}Handling Quota Exceeded
Section titled “Handling Quota Exceeded”When your monthly scan quota is exhausted, session creation returns a 429 with a different error code:
{ "error": "QUOTA_EXCEEDED", "message": "Monthly scan quota exceeded", "retryable": false}Monitoring Usage
Section titled “Monitoring Usage”You can check your current usage at any time via the developer API:
curl https://api.circadify.com/developer/usage \ -H "Authorization: Bearer YOUR_TOKEN"Response:
{ "current_month": { "scan_count": 42 }, "limit": 500, "remaining": 458, "plan": "starter"}For historical usage:
curl https://api.circadify.com/developer/usage/history \ -H "Authorization: Bearer YOUR_TOKEN"Response:
{ "history": [ { "month": "2026-04", "scan_count": 42 }, { "month": "2026-03", "scan_count": 387 }, { "month": "2026-02", "scan_count": 215 } ]}Best Practices
Section titled “Best Practices”- Monitor remaining requests via
X-RateLimit-Remainingheaders to avoid hitting limits - Monitor remaining scans via
X-Usage-Remainingto plan around monthly quotas - Implement backoff — never retry immediately on a 429 response
- Cache results — once you retrieve session results, store them on your side. Don’t poll repeatedly for the same session
- Use test keys (
ck_test_*) during development to avoid consuming production quotas
Upgrading Your Plan
Section titled “Upgrading Your Plan”If you consistently hit rate limits or quota limits, upgrade your plan in the developer dashboard or contact sales@circadify.com for enterprise pricing.
Next Steps
Section titled “Next Steps”- Errors — Full error reference
- Sessions — Session endpoints
- REST API Overview — API basics