Rate Limits
logi applies rate limits in two layers:
- Cloudflare edge — IP-based, blocking requests before they reach the app (active in deployed environments).
- Rails server (rack-attack) — keyed by a specific identifier (
client_id,user_id, or IP), returning a JSON 429.
The Rails layer uses Rails.cache (SolidCache in production) as its store, so it works without separate Redis infrastructure.
Per-endpoint limits
| Endpoint | Limit | Key | Layer | Notes |
|---|---|---|---|---|
POST /session (login) | 10 / 3min | IP | Rails | Brute-force defense |
POST /oauth/authorize | 30 / min | IP | Rails + Cloudflare | |
POST /oauth/token | 20 / min | client_id | Rails | Falls back to IP if client_id is missing |
POST /api/v1/me/otp/* | 10 / min | session/user | Rails | Defends against SMS cost spikes |
POST /api/v1/me/passkeys/* | 20 / min | session/user | Rails | |
POST /api/v1/devices | 10 / min | IP | Rails | Device-bootstrap brute-force defense |
POST /api/v1/users/:sub/identity_verified | 100 / hour | client_id (Bearer hash) | Rails | Per reporter app |
Other /api/* | 60 / min | IP | Rails | Global fallback |
Static/Health (/up, /healthz) | Unlimited | — | safelist |
Response when exceeded
http
HTTP/2 429 Too Many Requests
Content-Type: application/json
{"error":"rate_limited"}Some endpoints may include a Retry-After header.
Client recommendations
- Exponential backoff: on a 429, prefer the
Retry-Afterheader; if it's absent, retry with widening intervals of 1 → 2 → 4 → 8 seconds. - You'll rarely hit these limits in normal flows — persistent 429s suggest an implementation bug (a retry loop).
- For workloads where bursts are expected, consult us in advance (per-app custom limits are planned for Phase 2).
Implementation details
The server-side implementation lives in server/config/initializers/rack_attack.rb. When a limit changes, update both that file and this document together.
In the test environment, Rails.cache is null_store, so throttling is disabled. To test the rate limiting itself, swap in a MemoryStore as in spec/requests/rate_limit_spec.rb.