Every request is rate-limited by an in-memory sliding-window counter — no external dependency (no Redis, no slowapi). Limits are per caller identity, not global:
- Authenticated calls are keyed by a hash of the Bearer token (API key, session, or master key).
- Unauthenticated calls (before any credential is known to be valid, e.g. a login attempt) are keyed by source IP.
This means one noisy caller can’t exhaust another caller’s quota, and an unauthenticated brute-force attempt against /v1/auth/login is throttled per-IP even before it ever presents a valid credential.
Limits
The auth tier is intentionally tighter — these are the endpoints someone would actually try to brute-force (login) or spam (registration).
Response when limited
A 429 with a structured body and a standard Retry-After header (seconds until the window frees up):
Same error envelope as every other error in this API.
Single-process only. Counters live in this process’s memory. If this API ever runs with multiple uvicorn workers or multiple replicas behind a load balancer, each process keeps its own counters — the effective limit multiplies by however many processes are running. Fine for a single-instance deployment (e.g. one Railway service); move to a shared store (Redis) first if you scale horizontally.