## Changes - Add narrative API documentation in docs/api-content/ (introduction, quickstart, authentication, conventions, errors, rate limiting) - Scaffold Astro Starlight site at docs/api/ that consumes prose from the sibling api-content folder and auto-generates the endpoint reference from server/openapi.json via starlight-openapi - Wire Checkmate brand color (#13715B) into Starlight via custom CSS - Add vercel.json so the docs site deploys cleanly as an Astro project with root directory docs/api/ ## Benefits - Public API docs ready to publish at checkmate.so/docs - Endpoint reference stays in sync with the OpenAPI spec automatically - Zero third-party SaaS dependency: site is fully self-hosted on Vercel - Contributors edit plain markdown; no Astro knowledge needed for prose
4.0 KiB
title, description
| title | description |
|---|---|
| Authentication | Obtain a JWT from /auth/login and send it as a Bearer token on every subsequent request. |
Authentication
Checkmate uses JWT bearer tokens. There are no API keys, no OAuth, and no client secrets. Every API user is a regular Checkmate user — the credentials you log in to the web UI with are the credentials you use to obtain a token.
The flow
- Get a token by calling
POST /auth/loginwith your email and password. - Send the token as
Authorization: Bearer <token>on every subsequent request. - Refresh by calling
POST /auth/loginagain before the token expires.
Obtaining a token
curl -X POST https://your-checkmate-host/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"password": "YourPass1!"
}'
A successful response returns the token plus the authenticated user record:
{
"success": true,
"msg": "OK",
"data": {
"user": {
"_id": "65f1c2a4d8b9e0123456789a",
"firstName": "Ada",
"lastName": "Lovelace",
"email": "you@example.com",
"role": ["admin"],
"teamId": "65f1c2a4d8b9e01234567890",
"createdAt": "2026-04-01T10:00:00.000Z",
"updatedAt": "2026-04-15T14:30:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Store both token (for the Authorization header) and user.teamId (most resource endpoints are scoped by team).
Using a token
Every authenticated request must include:
Authorization: Bearer <token>
curl https://your-checkmate-host/api/v1/monitors/team/<teamId> \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
const res = await fetch("https://your-checkmate-host/api/v1/monitors/team/<teamId>", {
headers: { Authorization: `Bearer ${token}` },
});
Token lifetime
Tokens expire after the duration configured by the operator via the TOKEN_TTL environment variable. The default is 99 days.
There is no separate refresh-token endpoint. When a token is close to expiry — or after a 401 response — call POST /auth/login again to obtain a new one.
Roles
The user.role claim is an array. Available roles:
| Role | Capability |
|---|---|
superadmin |
Full access to all teams and global settings. Can promote other users. |
admin |
Full access within their team. |
user |
Read access within their team. |
demo |
Limited demo-mode access. |
A user can hold multiple roles simultaneously.
Registering the first user
A fresh Checkmate instance has no users. The first call to POST /auth/register creates the first superadmin and provisions a team for them:
curl -X POST https://your-checkmate-host/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"firstName": "Ada",
"lastName": "Lovelace",
"email": "ada@example.com",
"password": "Hunter2!",
"role": ["superadmin"],
"teamId": ""
}'
After the first user exists, additional users are usually created via the invite flow rather than POST /auth/register:
POST /invite/send # superadmin/admin sends an invite
POST /auth/register # invitee redeems the invite token
You can check whether a superadmin already exists with:
curl https://your-checkmate-host/api/v1/auth/users/superadmin
{ "success": true, "data": true }
Password recovery
The password-recovery flow is three calls, all unauthenticated:
POST /auth/recovery/request # user requests a recovery email
POST /auth/recovery/validate # client validates the recovery token
POST /auth/recovery/reset # user sets a new password
Logging out
JWTs are stateless — there is no server-side logout. Drop the token from your client storage. If you need to invalidate a token before its expiry (e.g. a compromised device), the operator must rotate the JWT_SECRET environment variable, which invalidates every outstanding token.
Next: Conventions.