Middleware & Policies
Rate Limiting
Section titled “Rate Limiting”Rate limits are enforced per-tenant using a Redis sliding window counter.
| Scope | Window | Limit |
|---|---|---|
| Authenticated requests | 60 seconds | 300 per tenant |
| Unauthenticated requests | 60 seconds | 30 per IP |
Rate limit headers are included on every authenticated response:
X-RateLimit-Limit: 300X-RateLimit-Remaining: 285X-RateLimit-Reset: 1738900860When the limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating seconds until the next window.
Request Tracing
Section titled “Request Tracing”Every request receives a unique request ID for distributed tracing:
- If the client sends an
X-Request-Idheader, the server uses that value - Otherwise, the server generates
req_{ULID}(e.g.,req_01ARZ3NDEKTSV4RRFFQ69G5FAV) - The request ID appears in the response
X-Request-Idheader and in theinstancefield of all error responses
Idempotency
Section titled “Idempotency”POST endpoints that create resources accept an optional Idempotency-Key header (UUID). Duplicate requests with the same key return the stored response without re-executing. Keys are stored for 24 hours.
Idempotency is scoped to the authenticated tenant: the cache is keyed on your tenant plus the key, so an Idempotency-Key you choose can never collide with another tenant’s. It is also fail-closed — requests with no authenticated tenant (public, guest, and webhook endpoints) are never cached at all, rather than sharing a common namespace. Those endpoints have their own replay protection: the Gitea webhook, for example, verifies an HMAC-SHA256 X-Gitea-Signature.
PUT, DELETE, and GET are naturally idempotent.
| Setting | Value |
|---|---|
| Allowed origins | Configurable via AKILI_CORS_ORIGINS env var |
| Allowed methods | GET, POST, PUT, PATCH, DELETE, OPTIONS |
| Allowed headers | Authorization, Content-Type, X-Request-Id, X-Tenant-Id |
| Exposed headers | X-Request-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
| Max age | 3600 seconds |
| Credentials | true |