Rate limits and quotas
How many requests you can make and what happens when you hit a limit.
Limits depend on your plan and are counted per API key.
Requests per minute#
A rolling one-minute window per key. Every successful response carries X-RateLimit-Remaining with the requests left in the current window. Above the limit you get 429 rateLimited with error.retryAfter in seconds.
X-RateLimit-Remaining: 59{
"error": {
"code": "rateLimited",
"message": "Rate limit exceeded",
"retryAfter": 12
}
}Monthly quota#
Each key has a monthly request quota that resets on the 1st of every month at 00:00 UTC. When it runs out, requests return 429 rateLimited with error.reason set to quota until the next month.
{
"error": {
"code": "rateLimited",
"message": "Monthly quota exceeded",
"reason": "quota"
}
}Daily scans#
A POST /scans call that actually starts a scan uses one scan from your plan's daily scan limit, shared with scans you start in the app. Reading reports, and scan calls that return a fresh cached report, don't use the scan limit (they still count as API requests).
Limits by plan#
| Plan | Requests / minute | Requests / month |
|---|---|---|
Pro | 60 | 100,000 |
Best practices#
- Cache token reports on your side; a report stays fresh for several minutes.
- On 429, wait for
retryAfterseconds, then retry with exponential backoff and jitter. - Poll scans every 3–5 seconds, not in a tight loop.
- Spread batch jobs over time instead of firing them in parallel.