/, /health, and the signup and login routes.
The JWT carries
sub (email), email, org_id, and role. org_id is the active organisation — a user in several organisations holds one token per organisation and swaps with POST /api/v1/users/switch-organisation. Tokens are signed with SECRET_KEY using JWT_ALGORITHM and expire after ACCESS_TOKEN_EXPIRE_MINUTES.
Role checks are not dependencies. They are explicit HTTPException raises inside the handler after the token has been verified, so an authenticated caller with the wrong role gets 403, never 401.
X-API-Key returns 401 Missing API key when the header is absent, 401 Invalid API key when it does not match, and 500 Internal API key not configured when INTERNAL_API_KEY is unset on the server.
Getting a token
POST /api/v1/users/signup creates the user, an organisation, and a super_admin membership in one step. There is no seeded default account.
Roles
Organisation scoping
Every organisation-scoped route readsorg_id from the token, not from the request. Routes that also take org_id in the path — GET /api/v1/members/{org_id}, GET /api/v1/calls/org/{org_id} — check membership separately and return 403 when you are not a member. A token with no org_id claim gets 400 No active organisation in token from the routes that require one.
Related
- Users and organisations — the routes that issue and swap tokens
- Multi-tenancy and roles — the model behind this
- Errors