The three controls
- Rate limits — requests per second / minute / day, and max concurrency. Token-bucket
counters allow short bursts (a
burst_multiplier) while bounding the sustained rate. - Quotas — a count per fixed calendar window (day or month) on one of these metrics:
requests,input_tokens,output_tokens,total_tokens, orcost_usd. A quota is pre-checked with an estimate, then corrected with actuals by the metering pipeline. - Budgets — a spend cap in USD, enforced with a reserve/settle scheme so many concurrent requests cannot collectively blow past the cap.
Scopes and precedence
A policy can be attached at several scopes. For each dimension the gateway evaluates the most specific policy that applies, in this order:Soft vs hard limits (the kill-switch)
Every threshold is either soft or hard:
Windows are fixed and keyed by UTC date; counters self-expire, so there is no reset job.
Alerts are delivered by email to the account owner. Roadie does not send outbound
webhooks for limit or budget events.
Rate-limit response headers
Every data-plane response carries the most-constrained window’s state:X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset(epoch seconds)Retry-After(on429)
result.rateLimit and, on errors, err.retryAfter.
Handling limit errors
429 responses (honoring Retry-After) up to maxRetries — and
because both rate_limit_error and quota_error are 429, the SDK retries both; either one
reaches your catch only after those retries are exhausted. A quota retry can’t succeed until
the window resets, so a QuotaError still surfaces (just after a few short waits). budget_error
is 402, so it is not retried — it surfaces immediately.
On the OpenAI-compatible surface, both quota and budget rejections
are reported as
insufficient_quota at 429, because the OpenAI error schema has no 402.
The native surface keeps them distinct (quota_error at 429, budget_error at 402).