Rate limits
Requests are rate-limited per API key (key management, which uses a dashboard session, is limited per user). Limits protect the platform’s shared capacity; they are independent of your budget, which limits spend rather than frequency.
Buckets
| Bucket | Limit | Window | Applies to |
|---|---|---|---|
| reads | 60 | 1 minute | Every GET except the SSE stream and /v1/keys/*, plus POST /v1/scans/estimate |
| mutations | 30 | 1 minute | POST /v1/scans/{id}/cancel, DELETE /v1/exports/{id} |
| scans | 6 | 1 hour | POST /v1/scans |
| exports | 30 | 1 hour | POST /v1/exports |
| key management | 10 | 1 minute | /v1/keys/* (per user, dashboard session) |
GET /v1/scans/{id}/stream is not rate-limited — hold one long-lived stream per scan rather than polling tightly.
The scans bucket is deliberately small: 6 scan creations per hour per key. POST /v1/scans/estimate costs nothing from it — estimate freely, scan deliberately. A 429 from this bucket can mean waiting up to an hour, so schedule batch work accordingly.
Response headers
Successful responses on limited endpoints carry the IETF draft-7 standard headers:
RateLimit-Policy: 60;w=60
RateLimit: limit=60, remaining=57, reset=42RateLimit-Policy— the bucket’s policy: limit and window (seconds).RateLimit— your current state:limit,remainingrequests, and seconds untilreset.
When you are limited
A 429 returns a problem-details body plus a Retry-After header (in seconds):
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
Content-Type: application/problem+json; charset=utf-8
{
"type": "https://api.regsn.app/problems/rate_limited",
"title": "Rate limit exceeded",
"status": 429,
"detail": "Rate limit exceeded for scans bucket. Retry after 3600s.",
"instance": "/v1/scans",
"code": "rate_limit_exceeded",
"request_id": "req_m3k9…",
"errors": []
}Client guidance:
- Honour
Retry-After. Both SDKs do this automatically (capped at 60 seconds per wait, up to 3 retries). - Watch
remainingon theRateLimitheader and pace proactively instead of driving into the limit. - Pair retries with idempotency. A retried
POST /v1/scansorPOST /v1/exportswith the sameIdempotency-Keycan never double-run work. - Prefer streaming to polling for scan progress — the stream is unmetered; polling spends the reads bucket.
See also
- Errors — the
429body shape and every other code. - Usage & budget — spend limits, as opposed to frequency limits.