Rate limits
Per-key sliding-window limits + tier ceilings.
CiteFlow enforces a sliding-window rate limit per API key, per endpoint. Each key has its own bucket — your CI key hitting the wall won't deplete your production key's budget.
The tier ceiling is derived from lifetime_purchased credits, so you
auto-promote into higher limits as you spend more.
Tier ceilings
| Endpoint | Starter | Growth | Scale | Enterprise |
|---|---|---|---|---|
POST /audit | 30/min · 1k/day | 60/min · 5k/day | 200/min · 25k/day | 1k/min · unlimited |
GET /audit/{id} | 300/min | 600/min | 1.2k/min | 6k/min |
GET /balance | 60/min | 60/min | 60/min | 60/min |
POST /audit/{id}:cancel | 30/min | 60/min | 200/min | 600/min |
POST /billing/topup | 10/min · 100/day | 10/min · 100/day | 20/min · 200/day | 60/min |
POST /webhooks/deliveries/{id}/replay | 10/min | 10/min | 30/min | 60/min |
Sliding-window algorithm allows ~10% burst above the documented limit; do not depend on the burst. The window slides continuously, so spreading load is always better than spiking.
Headers on every response
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 27
X-RateLimit-Reset: 1748400060| Header | Meaning |
|---|---|
X-RateLimit-Limit | The current cap. |
X-RateLimit-Remaining | Calls left before the next reset. |
X-RateLimit-Reset | Unix epoch (seconds) when the window rolls. |
When you hit the wall:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Remaining: 0{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded for POST /audit. Retry after 12s.",
"retryAfter": 12
}
}Tier derivation
Tier comes from cumulative lifetime_purchased:
| Lifetime purchased | Tier |
|---|---|
| < 20,900 (Starter) | starter |
| ≥ 20,900 | growth |
| ≥ 54,900 | scale |
| ≥ 100,000 | enterprise |
Top up to instantly raise your ceiling — the tier check happens on the hot path.
Per-key overrides
Enterprise customers and customers experiencing incidents can request
temporary per-key overrides via partners@citeflow.io. Overrides live
in partner_api_keys.rate_limit_overrides and never expose other
partners' settings.
Best practices
- Spread sustained load — sliding window punishes spikes.
- Pre-flight
GET /balancewhen in doubt beforePOST /audit; 402 has cost (rate-limited too) but the balance call is cheap. - Use webhooks instead of polling —
GET /audit/{id}allows generous polling rates, but webhooks are still cheaper and faster. - Backoff on 429 — exponential with jitter, never tight-loop retry. The SDK does this for you.