Rate limits
Per-tenant, per-endpoint request throttling — glob-matched policies with block, throttle, or log-only enforcement and an incident log.
Rate limits
Rate limits let you cap request volume per endpoint for your tenant. Policies are sliding-window counters matched by URL glob, with a choice of enforcement, and every breach is recorded so you can see who hit a limit and when.
The control lives at Admin → Rate limits and is backed by
core.tenant_rate_limit, applied in the request path by
api/rate_limit_middleware.py.
Real middleware enforcement
Policies are read on the request path through a 60-second in-process TTL cache and counted in Redis (or an in-process backend in dev) for cross-replica consistency. Matching requests are counted and enforced before the handler runs.
How policies match
Each policy has an endpoint_pattern glob. The most specific match wins:
/v1/email/send → exact match (highest specificity)
/v1/email/* → prefix glob
* → global catch-all (default policy)
When several policies match, the longest-prefix / exact match takes precedence; ties break toward the lowest policy id.
Enforcement modes
Each policy sets one of:
block— reject requests over the limit (HTTP 429).throttle— slow rather than hard-reject.log_only— count and record, but never reject. Use this to size a limit against real traffic before turning on enforcement.
Fail-open by design
Rate limiting never blocks legitimate traffic on error
Every public function in the enforcement path catches exceptions and returns a
permissive result rather than crashing the request. A misconfigured Redis or a
stale cache degrades to "allow", not "500". auth.rate_limit.exceeded
audit events are also sampled — at most one per 100 occurrences per
(tenant, policy) — so a sustained attack can't flood the audit table.
API
Admin/owner only (Permission.ADMIN_FLAGS), tenant-scoped from the auth context
— you can never read or write another tenant's policies:
GET /v1/rate-limits/policies # list this tenant's policies
POST /v1/rate-limits/policies # create a policy
PATCH /v1/rate-limits/policies/{id} # update a policy
DELETE /v1/rate-limits/policies/{id} # delete a policy
POST /v1/rate-limits/policies/seed-defaults# seed a sensible default set
GET /v1/rate-limits/incidents # recent rate-limit-exceeded events
GET /v1/rate-limits/analytics # aggregated breach analytics
GET /v1/rate-limits/usage # current usage vs. limits
GET /v1/rate-limits/usage/banner # per-user near-limit banner signal
A policy takes requests_per_window (1…100,000), window_seconds
(1…86,400, default 60), endpoint_pattern (default *), enforcement, and
enabled. Policies are stored in tenant_rate_limit_policies
(alembic 0104_tenant_rate_limit_policies).
Distinct from AI call-rate limits
These are HTTP-endpoint limits. The per-minute call-rate limits on AI features are a separate, in-memory gate configured on the AI budget page — don't confuse the two.