Accounts and sessions for your app: register, verify the email address, log in, refresh, log out, reset a forgotten password, and manage accounts as an admin.
Authentication. Log in to get an access token and a refresh token. Send the access token with each request as Authorization: Bearer <accessToken>; it lasts minutes. When it expires, exchange the refresh token at POST /api/v1/auth/refresh for a new pair. Each refresh token works once: presenting a used one again ends the whole session, because it means someone else has a copy.
Errors all have one shape (ErrorResponse), with a code to branch on.
Rate limits. Each address may make a limited number of requests a minute, and fewer to the routes worth guessing at (logging in, registering, the ones that send email). Over the limit, the answer is 429.
Auth
Registering, logging in and out, tokens, and password resets.
Create an account
POST /api/v1/auth/register Public
Creates the account and emails a link to verify the address. With REQUIRE_VERIFIED_EMAIL on (the default), the account can log in once the address is verified.
Request body RegisterRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
password | string | At least 10 characters. 10–128 characters. |
name | string | The name to greet the user by. 1–100 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/register \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"correct-horse-battery","name":"Ada Lovelace"}'
Responses
201 Created. A verification email is on its way.
{ "user": { "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }, "message": "Check your email for a link to verify your address." }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }409 An account already uses this address (
email_taken).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Verify an email address
POST /api/v1/auth/verify-email Public
Takes the token from the link in the verification email. Each token works once, for 24 hours.
Request body TokenRequest
| Field | Type | Notes |
|---|---|---|
token | string | The token from the link in the email. 20–200 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/verify-email \
-H 'Content-Type: application/json' \
-d '{"token":"q3Bf1cQ9…"}'
Responses
200 Verified.
{ "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }400 The token is invalid, used or expired (
invalid_token).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Send the verification email again
POST /api/v1/auth/resend-verification Public
Answers the same whether or not the address has an account, so it can’t be used to find out. The earlier link stops working.
Request body EmailRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/resend-verification \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com"}'
Responses
202 Accepted.
{ "message": "If an account uses this address, an email is on its way." }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Log in
POST /api/v1/auth/login Public
Starts a session and returns an access token (short-lived; send it with each request) and a refresh token (long-lived; exchange it at /auth/refresh when the access token expires).
Request body LoginRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
password | string | 1–128 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"correct-horse-battery"}'
Responses
200 Logged in.
{ "user": { "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }, "tokens": { "tokenType": "Bearer", "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…", "accessTokenExpiresAt": "2026-10-01T09:30:00.000Z", "refreshToken": "Vh4k2n8…", "refreshTokenExpiresAt": "2026-10-01T09:30:00.000Z" } }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 Wrong email address or password (
invalid_credentials).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }403 The address isn’t verified yet (
email_not_verified).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Exchange a refresh token for a new pair
POST /api/v1/auth/refresh Public
Each refresh token works once: this returns the next one. If a used refresh token is presented again, someone else has a copy, so the whole session is ended (refresh_token_reused) and the user logs in again.
Request body RefreshRequest
| Field | Type | Notes |
|---|---|---|
refreshToken | string | The refresh token from the last login or refresh. Each one works once. 20–200 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/refresh \
-H 'Content-Type: application/json' \
-d '{"refreshToken":"Vh4k2n8…"}'
Responses
200 A new access token and refresh token.
{ "tokenType": "Bearer", "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…", "accessTokenExpiresAt": "2026-10-01T09:30:00.000Z", "refreshToken": "Vh4k2n8…", "refreshTokenExpiresAt": "2026-10-01T09:30:00.000Z" }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 The refresh token is unknown or expired (
refresh_token_invalid), was already used (refresh_token_reused), or its session has ended (session_revoked).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Log out
POST /api/v1/auth/logout Needs an access token
Ends this session. Its access token and refresh token stop working at once.
Example
curl -X POST http://localhost:3000/api/v1/auth/logout \
-H 'Authorization: Bearer <accessToken>'
Responses
204 Logged out.
No body.
401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Log out everywhere
POST /api/v1/auth/logout-all Needs an access token
Ends every session of this account, on every device, this one included.
Example
curl -X POST http://localhost:3000/api/v1/auth/logout-all \
-H 'Authorization: Bearer <accessToken>'
Responses
204 Logged out everywhere.
No body.
401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Email a password-reset link
POST /api/v1/auth/forgot-password Public
Answers the same whether or not the address has an account. The link works once, for an hour; asking again replaces it.
Request body EmailRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/forgot-password \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com"}'
Responses
202 Accepted.
{ "message": "If an account uses this address, an email is on its way." }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Choose a new password
POST /api/v1/auth/reset-password Public
Takes the token from the reset email and the new password. Every session of the account ends, and the address counts as verified.
Request body ResetPasswordRequest
| Field | Type | Notes |
|---|---|---|
token | string | The token from the link in the email. 20–200 characters. |
password | string | At least 10 characters. 10–128 characters. |
Example
curl -X POST http://localhost:3000/api/v1/auth/reset-password \
-H 'Content-Type: application/json' \
-d '{"token":"q3Bf1cQ9…","password":"correct-horse-battery"}'
Responses
204 The password is changed. Log in with it.
No body.
400 A field is invalid, or the token is invalid, used or expired (
invalid_token).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }429 Too many attempts from this address. Wait a minute.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Account
The signed-in user’s own account and sessions.
Your account
GET /api/v1/users/me Needs an access token
Example
curl -X GET http://localhost:3000/api/v1/users/me \
-H 'Authorization: Bearer <accessToken>'
Responses
200 The signed-in user.
{ "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Change your name
PATCH /api/v1/users/me Needs an access token
Request body UpdateProfileRequest
| Field | Type | Notes |
|---|---|---|
name | string | The name to greet the user by. 1–100 characters. |
Example
curl -X PATCH http://localhost:3000/api/v1/users/me \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-d '{"name":"Ada Lovelace"}'
Responses
200 Updated.
{ "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Change your password
POST /api/v1/users/me/password Needs an access token
Needs the current password. Every other session ends; this one stays logged in.
Request body ChangePasswordRequest
| Field | Type | Notes |
|---|---|---|
currentPassword | string | 1–128 characters. |
newPassword | string | At least 10 characters. 10–128 characters. |
Example
curl -X POST http://localhost:3000/api/v1/users/me/password \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-d '{"currentPassword":"correct-horse-battery","newPassword":"correct-horse-battery"}'
Responses
204 Changed.
No body.
400 A field is invalid, or the current password is wrong (
wrong_password).{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Where you are logged in
GET /api/v1/users/me/sessions Needs an access token
Every session that can still be used, newest first, with the one making this request marked current.
Example
curl -X GET http://localhost:3000/api/v1/users/me/sessions \
-H 'Authorization: Bearer <accessToken>'
Responses
200 The sessions.
{ "sessions": [ { "id": "string", "createdAt": "2026-10-01T09:30:00.000Z", "lastUsedAt": "2026-10-01T09:30:00.000Z", "expiresAt": "2026-10-01T09:30:00.000Z", "userAgent": "Mozilla/5.0 (iPhone; …)", "ip": "203.0.113.7", "current": true } ] }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Log out one device
DELETE /api/v1/users/me/sessions/{id} Needs an access token
Ends one of your sessions: a lost phone, a shared computer.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
id | path | string |
Example
curl -X DELETE http://localhost:3000/api/v1/users/me/sessions/:id \
-H 'Authorization: Bearer <accessToken>'
Responses
204 Ended.
No body.
401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }404 You have no such session.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Admin
Managing accounts. Admins only.
List accounts
GET /api/v1/admin/users Needs an access token
Newest first, a page at a time, optionally filtered.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
page optional | query | integer | From 1. At least 1; default 1. |
pageSize optional | query | integer | 1 to 100; default 20. |
search optional | query | string | Part of an email address or a name. Up to 100 characters. |
role optional | query | string | What the user may do. One of USER, ADMIN. |
Example
curl -X GET http://localhost:3000/api/v1/admin/users \
-H 'Authorization: Bearer <accessToken>'
Responses
200 One page of accounts.
{ "items": [ { "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" } ], "page": 1, "pageSize": 1, "total": 1 }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }403 The account’s role doesn’t allow this.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Change an account’s role
PATCH /api/v1/admin/users/{id}/role Needs an access token
It applies to the account’s next request. You can’t change your own.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
id | path | string |
Request body UpdateRoleRequest
| Field | Type | Notes |
|---|---|---|
role | string | What the user may do. One of USER, ADMIN. |
Example
curl -X PATCH http://localhost:3000/api/v1/admin/users/:id/role \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-d '{"role":"USER"}'
Responses
200 Changed.
{ "id": "cmg3x9k2a0000abcd1234efgh", "email": "ada@example.com", "name": "Ada Lovelace", "role": "USER", "emailVerified": true, "createdAt": "2026-10-01T09:30:00.000Z" }400 A field is missing or invalid.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }401 No access token, or it has expired, or its session was revoked. Refresh and retry.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }403 Not an admin, or it’s your own account.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }404 No such record.
{ "statusCode": 400, "error": "Bad Request", "code": "validation_failed", "message": "Some fields are missing or invalid.", "issues": [ { "path": "password", "message": "Use at least 10 characters." } ] }
Health
For load balancers and uptime checks.
Health check
GET /health Public
Example
curl -X GET http://localhost:3000/health
Responses
Schemas
RegisterRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
password | string | At least 10 characters. 10–128 characters. |
name | string | The name to greet the user by. 1–100 characters. |
Example
{
"email": "ada@example.com",
"password": "correct-horse-battery",
"name": "Ada Lovelace"
}LoginRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
password | string | 1–128 characters. |
Example
{
"email": "ada@example.com",
"password": "correct-horse-battery"
}RefreshRequest
| Field | Type | Notes |
|---|---|---|
refreshToken | string | The refresh token from the last login or refresh. Each one works once. 20–200 characters. |
Example
{
"refreshToken": "Vh4k2n8…"
}TokenRequest
| Field | Type | Notes |
|---|---|---|
token | string | The token from the link in the email. 20–200 characters. |
Example
{
"token": "q3Bf1cQ9…"
}EmailRequest
| Field | Type | Notes |
|---|---|---|
email | string, email | An email address. Up to 191 characters. |
Example
{
"email": "ada@example.com"
}ResetPasswordRequest
| Field | Type | Notes |
|---|---|---|
token | string | The token from the link in the email. 20–200 characters. |
password | string | At least 10 characters. 10–128 characters. |
Example
{
"token": "q3Bf1cQ9…",
"password": "correct-horse-battery"
}UpdateProfileRequest
| Field | Type | Notes |
|---|---|---|
name | string | The name to greet the user by. 1–100 characters. |
Example
{
"name": "Ada Lovelace"
}ChangePasswordRequest
| Field | Type | Notes |
|---|---|---|
currentPassword | string | 1–128 characters. |
newPassword | string | At least 10 characters. 10–128 characters. |
Example
{
"currentPassword": "correct-horse-battery",
"newPassword": "correct-horse-battery"
}UpdateRoleRequest
| Field | Type | Notes |
|---|---|---|
role | string | What the user may do. One of USER, ADMIN. |
Example
{
"role": "USER"
}User
An account, without anything secret.
| Field | Type | Notes |
|---|---|---|
id | string | |
email | string, email | An email address. Up to 191 characters. |
name | string | The name to greet the user by. 1–100 characters. |
role | string | What the user may do. One of USER, ADMIN. |
emailVerified | boolean | |
createdAt | string, date-time |
Example
{
"id": "cmg3x9k2a0000abcd1234efgh",
"email": "ada@example.com",
"name": "Ada Lovelace",
"role": "USER",
"emailVerified": true,
"createdAt": "2026-10-01T09:30:00.000Z"
}Tokens
A new pair: use the access token, keep the refresh token.
| Field | Type | Notes |
|---|---|---|
tokenType | string | One of Bearer. |
accessToken | string | Send it as Authorization: Bearer <accessToken>. A JWT. |
accessTokenExpiresAt | string, date-time | |
refreshToken | string | The refresh token from the last login or refresh. Each one works once. 20–200 characters. |
refreshTokenExpiresAt | string, date-time |
Example
{
"tokenType": "Bearer",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
"accessTokenExpiresAt": "2026-10-01T09:30:00.000Z",
"refreshToken": "Vh4k2n8…",
"refreshTokenExpiresAt": "2026-10-01T09:30:00.000Z"
}LoginResponse
Example
{
"user": {
"id": "cmg3x9k2a0000abcd1234efgh",
"email": "ada@example.com",
"name": "Ada Lovelace",
"role": "USER",
"emailVerified": true,
"createdAt": "2026-10-01T09:30:00.000Z"
},
"tokens": {
"tokenType": "Bearer",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
"accessTokenExpiresAt": "2026-10-01T09:30:00.000Z",
"refreshToken": "Vh4k2n8…",
"refreshTokenExpiresAt": "2026-10-01T09:30:00.000Z"
}
}RegisterResponse
| Field | Type | Notes |
|---|---|---|
user | User | |
message | string |
Example
{
"user": {
"id": "cmg3x9k2a0000abcd1234efgh",
"email": "ada@example.com",
"name": "Ada Lovelace",
"role": "USER",
"emailVerified": true,
"createdAt": "2026-10-01T09:30:00.000Z"
},
"message": "Check your email for a link to verify your address."
}MessageResponse
| Field | Type | Notes |
|---|---|---|
message | string |
Example
{
"message": "If an account uses this address, an email is on its way."
}Session
| Field | Type | Notes |
|---|---|---|
id | string | |
createdAt | string, date-time | |
lastUsedAt | string, date-time | |
expiresAt | string, date-time | |
userAgent | string, or null | |
ip | string, or null | |
current | boolean | The session this request was made with. |
Example
{
"id": "string",
"createdAt": "2026-10-01T09:30:00.000Z",
"lastUsedAt": "2026-10-01T09:30:00.000Z",
"expiresAt": "2026-10-01T09:30:00.000Z",
"userAgent": "Mozilla/5.0 (iPhone; …)",
"ip": "203.0.113.7",
"current": true
}SessionList
| Field | Type | Notes |
|---|---|---|
sessions | array of Session |
Example
{
"sessions": [
{
"id": "string",
"createdAt": "2026-10-01T09:30:00.000Z",
"lastUsedAt": "2026-10-01T09:30:00.000Z",
"expiresAt": "2026-10-01T09:30:00.000Z",
"userAgent": "Mozilla/5.0 (iPhone; …)",
"ip": "203.0.113.7",
"current": true
}
]
}UserPage
| Field | Type | Notes |
|---|---|---|
items | array of User | |
page | integer | |
pageSize | integer | |
total | integer |
Example
{
"items": [
{
"id": "cmg3x9k2a0000abcd1234efgh",
"email": "ada@example.com",
"name": "Ada Lovelace",
"role": "USER",
"emailVerified": true,
"createdAt": "2026-10-01T09:30:00.000Z"
}
],
"page": 1,
"pageSize": 1,
"total": 1
}Health
| Field | Type | Notes |
|---|---|---|
status | string | One of ok. |
database | string | One of up, down. |
Example
{
"status": "ok",
"database": "up"
}ErrorResponse
Every error has this shape.
| Field | Type | Notes |
|---|---|---|
statusCode | integer | |
error | string | |
code | string | What went wrong, for programs: validation_failed, invalid_credentials, email_not_verified, email_taken, invalid_token, refresh_token_invalid, refresh_token_reused, session_revoked, wrong_password, unauthorized, forbidden, not_found, rate_limited, internal_error. |
message | string | |
issues optional | array of object | For validation_failed: each field that is wrong. |
Example
{
"statusCode": 400,
"error": "Bad Request",
"code": "validation_failed",
"message": "Some fields are missing or invalid.",
"issues": [
{
"path": "password",
"message": "Use at least 10 characters."
}
]
}