Rate Limits & Quotas
BVE Gateway enforces per-key rate limits using a Cloudflare Durable Object (ApiKeyLimiter). Each API key gets its own DO instance, so limits are applied independently per key.
Limit types
Section titled “Limit types”| Limit | Scope | Default | Configurable | Enforced |
|---|---|---|---|---|
| RPM | Per minute | 60 | Yes (per key) | Yes |
| RPD | Per day | 10,000 | Yes (per key) | Yes |
| Monthly requests | Per calendar month | None | Yes (per key) | Yes |
| Monthly tokens | Per calendar month | None | Yes (per key) | Stored only |
RPM, RPD, and monthly request limits are enforced by the ApiKeyLimiter Durable Object. The monthly_token_limit field is stored in D1 but is not currently enforced — it exists for future use.
Defaults are set at key creation and can be customized via the rpm_limit, rpd_limit, monthly_limit, and monthly_token_limit fields in POST /admin/api-keys.
How rate limiting works
Section titled “How rate limiting works”- On each request, the auth middleware resolves the API key from D1.
- The quota middleware calls
ApiKeyLimiter.checkAndIncrement()on the DO instance for that key. - If any limit is exceeded, the request is rejected with
429. - If the DO call fails, the request is allowed (fail-open) to avoid blocking legitimate traffic.
Limit windows
Section titled “Limit windows”| Window | Resets |
|---|---|
| Minute | Rolling — each DO instance has a resetAt timestamp set 60 seconds ahead at window start |
| Day | UTC midnight |
| Month | First day of the next UTC month |
Rate limit error
Section titled “Rate limit error”When a limit is exceeded, the response is:
HTTP/1.1 429 Too Many RequestsContent-Type: application/json{ "error": { "message": "Rate limit exceeded: requests per minute", "type": "rate_limit_error", "code": "rate_limit_exceeded" }}Possible error messages:
"Rate limit exceeded: requests per minute"— RPM limit hit"Rate limit exceeded: requests per day"— RPD limit hit"Monthly request limit exceeded"— monthly request cap hit
Worker-level caps
Section titled “Worker-level caps”In addition to per-key limits, the Worker has global request caps configured in wrangler.jsonc:
| Threshold | Value |
|---|---|
| Soft cap | 8,500,000 req/month |
| Hard cap | 9,500,000 req/month |
These are environment variable values (MONTHLY_WORKER_REQUEST_SOFT_CAP, MONTHLY_WORKER_REQUEST_HARD_CAP) and are not automatically enforced — they are available to monitoring/alerting logic.
Checking remaining quota (response headers)
Section titled “Checking remaining quota (response headers)”If Fuelix includes quota headers in its response, they are forwarded:
| Header | Description |
|---|---|
x-quota-allowed | Whether quota was allowed (from Fuelix) |
x-quota-available | Remaining quota (from Fuelix) |
x-quota-reset | Quota reset time (from Fuelix) |
BVE Gateway itself does not yet add remaining-quota headers to responses.