Rate limiting
API requests are rate limited to protect the platform and prevent a single tenant from degrading service for others ("noisy neighbor").
Headers
Throttled responses carry standard headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Request quota for the current window |
X-RateLimit-Remaining | Requests left in the current window |
Retry-After | Seconds to wait before retrying (on 429) |
Limits
| Scope | Default (per minute) | Keyed by | Env var |
|---|---|---|---|
| Global API | 120 | authenticated user id, else client IP | RATE_LIMIT_API |
| Per-tenant | 300 | tenant id (fair sharing across tenants) | RATE_LIMIT_TENANT |
| Auth (login, register, magic link, password reset) | 5 attempts | email + IP | (fixed) |
The numeric limits are environment-configurable via the env vars above. Treat
429 responses as authoritative and honor Retry-After.
Ordering and the noisy-neighbor limiter
The global limiter runs before authentication, so unauthenticated floods are throttled at the edge. The per-tenant limiter runs after the tenant context is resolved from the authenticated user, so its counter is keyed by the real tenant id — one tenant cannot exhaust another tenant's quota. Counters are backed by Redis in production.
Handling 429
On 429, back off for Retry-After seconds (or use exponential backoff if the
header is absent) before retrying. Never tight-loop on a throttled endpoint.