Docs
This is the exact contract the bundled apps/web expects from its backend — the cross-cutting mechanics that produce a confusing failure rather than a clean error when they’re wrong. Written for the frontend-only edition, but useful reading for anyone integrating against the API.
The frontend calls the API directly cross-origin — there is no same-origin proxy. Your backend needs CORS configured for the frontend’s origin with credentials enabled, since the refresh flow relies on a cookie.
POST /auth/login and POST /auth/refresh, held in memory client-side — never in localStorage.Sec-Fetch-Site header (falling back to Origin) before honoring it.User object
{
"id": "string",
"email": "string",
"globalRole": "SUPER_ADMIN" | "ADMIN" | "USER",
"hasPassword": true,
"avatar": "string | null"
}hasPassword is required — the account-deletion flow branches on it. Omitting it doesn’t error visibly; it silently routes every user down the wrong confirmation path.
Paginated list endpoints
{
"data": [ /* ... */ ],
"total": 0,
"page": 1,
"pageSize": 20,
"totalPages": 0,
"hasNextPage": false,
"hasPreviousPage": false
}A bare array here breaks every .filter()/.map() call on the response immediately.
Error responses
{
"statusCode": 400,
"error": "Bad Request",
"message": "Human-readable message, or an array of validation messages"
}Not required for the frontend to function, but if you rate-limit auth endpoints (recommended), return a 429 with a Retry-After header in seconds — the frontend doesn’t parse a custom retry payload.
This page covers integration mechanics, not every endpoint. For exact request/response shapes per route, reference the live Swagger UI generated at /api/docs once you have a full-stack or backend-only edition running — see Getting Started.