API Usage — Headers & Rate Limits
Required and optional headers, idempotency, CORS, rate limiting and exponential backoff.
API Usage — Headers & Rate Limits
This chapter covers HTTP headers, CORS rules and throttling. Read REST Conventions first.
Required headers
Frontend calls (Bearer + enriched)
httpAuthorization: Bearer <keycloak_access_token> x-enriched-token: <wakastart_token> Content-Type: application/json
Backend calls (API Key)
httpx-api-key: sk_live_... Content-Type: application/json
Optional headers
| Header | Description |
|---|---|
Accept-Language | Preferred language for error messages (fr, en). |
No
x-trace-id/x-request-id: these headers are not implemented to date (no occurrence onpublic-api,backend-for-front, ordiscovery). For a support incident, provide the timestamp, the route called, and the error response body.
CORS
The WakaStart API supports CORS for registered origins. The rules:
- Allowed origins: configured in
ALLOWED_ORIGINSon the API side. - Credentials:
Access-Control-Allow-Credentials: true— HttpOnly cookies are transmitted. - Methods:
GET,POST,PUT,PATCH,DELETE,OPTIONS. - Exposed headers:
Retry-After.
Direct calls from the browser: if your frontend calls the API without a proxy, the
wakastart_tokencookie isHttpOnlyand inaccessible from JavaScript. You cannot passx-enriched-tokenfrom the browser without a proxy. Always use a server-side proxy.
Idempotency
GET, PUT, and DELETE operations are idempotent. For POST:
- Invitation creation: if a
PENDINGinvitation already exists for the same email + Customer, the API responds409 Conflict. It is safe to retry after a network failure. - Enrichment:
/api/auth/enrichis idempotent for the same access_token within its validity period. - Token refresh:
/api/auth/token/refreshgenerates a new token on every call. Do not call it in parallel.
Rate limiting
The API applies three levels of throttling:
| Level | TTL | Limit | Description |
|---|---|---|---|
| Short | 1,000 ms | 10 req | Immediate anti-burst |
| Medium | 60,000 ms | 100 req | Per-minute limit |
| Long | 3,600,000 ms | 1,000 req | Per-hour limit |
Endpoint-specific limits
| Endpoint | Limit |
|---|---|
POST /discover/start-login | 5/60s · 20/600s (10 min) · 100/3600s (1 h) |
POST /api/auth/enrich | Not limited on the BFF side (no guard/throttler on this route) |
POST /api/auth/logout | Not limited on the BFF side (no guard/throttler on this route) |
POST /api/auth/token/refresh | 10/min (default of the BFF's ThrottlerModule, no specific rule) |
GET /api/invitations/verify/:token | 10/min/IP |
POST /api/invitations/accept/:token | 5/min/IP |
POST /api/mcp | 10/min |
429 Response:
json{ "statusCode": 429, "message": "Too Many Requests" }
The Retry-After header indicates the wait time in seconds.
Exponential backoff
typescriptasync function fetchWithRetry( url: string, options: RequestInit, maxRetries = 3 ): Promise<Response> { for (let attempt = 0; attempt < maxRetries; attempt++) { const res = await fetch(url, options); if (res.status !== 429) return res; const retryAfter = parseInt(res.headers.get("Retry-After") ?? "1", 10); const delay = retryAfter * 1000 * Math.pow(2, attempt); await new Promise(r => setTimeout(r, delay)); } throw new Error("Rate limit exceeded after retries"); }
Checking rights from your backend
httpPOST /api/token/authorize x-api-key: sk_live_... Content-Type: application/json { "token": "eyJ...", "checks": { "adminLevel": { "requiredLevel": "CustomerAdmin" }, "roles": { "roles": ["CONFIG"], "mode": "any" }, "appRights": { "rights": ["users.create"], "mode": "all" } } }
json{ "authorized": true, "details": { "adminLevel": { "hasLevel": true, "actualLevel": "NetworkAdmin" }, "roles": { "hasRoles": true, "matchedRoles": ["CONFIG"] }, "appRights": { "hasRights": true, "missingRights": [] } } }
Best practices
- Headers don't stack: a call with both
x-api-keyANDAuthorization: Bearerwill see the API key take precedence. - Log the error response body on 5xx (route, method,
statusCode,message): in the absence ofx-request-id, this is what lets support find the incident. - Respect
Retry-After: don't ignore this header, it protects the API's stability.
Common pitfalls
- Parallel calls to refresh: if several requests expire at the same time and all attempt a simultaneous refresh, only one succeeds. Implement a client-side mutex.
- Rate limit on tests: in CI, a batch of tests can trigger the short-duration rate limit. Add delays between integration tests.
Go further
- HTTP errors:
429and401codes in detail - Security best practices: tokens, secrets, HTTPS