Auth API 1.0.0

API reference · OpenAPI 3.0.0 · openapi.json · Base URL http://localhost:3000

Contents

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

FieldTypeNotes
emailstring, emailAn email address. Up to 191 characters.
passwordstringAt least 10 characters. 10–128 characters.
namestringThe 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.

    RegisterResponse

    {
      "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.

    ErrorResponse

    {
      "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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
tokenstringThe 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.

    User

    {
      "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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
emailstring, emailAn 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.

    MessageResponse

    {
      "message": "If an account uses this address, an email is on its way."
    }
  • 400 A field is missing or invalid.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
emailstring, emailAn email address. Up to 191 characters.
passwordstring1–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.

    LoginResponse

    {
      "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.

    ErrorResponse

    {
      "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).

    ErrorResponse

    {
      "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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
refreshTokenstringThe 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.

    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.

    ErrorResponse

    {
      "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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
emailstring, emailAn 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.

    MessageResponse

    {
      "message": "If an account uses this address, an email is on its way."
    }
  • 400 A field is missing or invalid.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
tokenstringThe token from the link in the email. 20–200 characters.
passwordstringAt 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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    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.

    ErrorResponse

    {
      "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

FieldTypeNotes
namestringThe 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.

    User

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

FieldTypeNotes
currentPasswordstring1–128 characters.
newPasswordstringAt 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).

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    SessionList

    {
      "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.

    ErrorResponse

    {
      "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

NameInTypeNotes
idpathstring

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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

NameInTypeNotes
page optionalqueryintegerFrom 1. At least 1; default 1.
pageSize optionalqueryinteger1 to 100; default 20.
search optionalquerystringPart of an email address or a name. Up to 100 characters.
role optionalquerystringWhat 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.

    UserPage

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

NameInTypeNotes
idpathstring

Request body UpdateRoleRequest

FieldTypeNotes
rolestringWhat 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.

    User

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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.

    ErrorResponse

    {
      "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

  • 200 Up, and the database answers.

    Health

    {
      "status": "ok",
      "database": "up"
    }
  • 503 Up, but the database doesn’t answer.

    Health

    {
      "status": "ok",
      "database": "up"
    }

Schemas

RegisterRequest

FieldTypeNotes
emailstring, emailAn email address. Up to 191 characters.
passwordstringAt least 10 characters. 10–128 characters.
namestringThe name to greet the user by. 1–100 characters.
Example
{
  "email": "ada@example.com",
  "password": "correct-horse-battery",
  "name": "Ada Lovelace"
}

LoginRequest

FieldTypeNotes
emailstring, emailAn email address. Up to 191 characters.
passwordstring1–128 characters.
Example
{
  "email": "ada@example.com",
  "password": "correct-horse-battery"
}

RefreshRequest

FieldTypeNotes
refreshTokenstringThe refresh token from the last login or refresh. Each one works once. 20–200 characters.
Example
{
  "refreshToken": "Vh4k2n8…"
}

TokenRequest

FieldTypeNotes
tokenstringThe token from the link in the email. 20–200 characters.
Example
{
  "token": "q3Bf1cQ9…"
}

EmailRequest

FieldTypeNotes
emailstring, emailAn email address. Up to 191 characters.
Example
{
  "email": "ada@example.com"
}

ResetPasswordRequest

FieldTypeNotes
tokenstringThe token from the link in the email. 20–200 characters.
passwordstringAt least 10 characters. 10–128 characters.
Example
{
  "token": "q3Bf1cQ9…",
  "password": "correct-horse-battery"
}

UpdateProfileRequest

FieldTypeNotes
namestringThe name to greet the user by. 1–100 characters.
Example
{
  "name": "Ada Lovelace"
}

ChangePasswordRequest

FieldTypeNotes
currentPasswordstring1–128 characters.
newPasswordstringAt least 10 characters. 10–128 characters.
Example
{
  "currentPassword": "correct-horse-battery",
  "newPassword": "correct-horse-battery"
}

UpdateRoleRequest

FieldTypeNotes
rolestringWhat the user may do. One of USER, ADMIN.
Example
{
  "role": "USER"
}

User

An account, without anything secret.

FieldTypeNotes
idstring
emailstring, emailAn email address. Up to 191 characters.
namestringThe name to greet the user by. 1–100 characters.
rolestringWhat the user may do. One of USER, ADMIN.
emailVerifiedboolean
createdAtstring, 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.

FieldTypeNotes
tokenTypestringOne of Bearer.
accessTokenstringSend it as Authorization: Bearer <accessToken>. A JWT.
accessTokenExpiresAtstring, date-time
refreshTokenstringThe refresh token from the last login or refresh. Each one works once. 20–200 characters.
refreshTokenExpiresAtstring, date-time
Example
{
  "tokenType": "Bearer",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "accessTokenExpiresAt": "2026-10-01T09:30:00.000Z",
  "refreshToken": "Vh4k2n8…",
  "refreshTokenExpiresAt": "2026-10-01T09:30:00.000Z"
}

LoginResponse

FieldTypeNotes
userUser
tokensTokens
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

FieldTypeNotes
userUser
messagestring
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

FieldTypeNotes
messagestring
Example
{
  "message": "If an account uses this address, an email is on its way."
}

Session

FieldTypeNotes
idstring
createdAtstring, date-time
lastUsedAtstring, date-time
expiresAtstring, date-time
userAgentstring, or null
ipstring, or null
currentbooleanThe 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

FieldTypeNotes
sessionsarray 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

FieldTypeNotes
itemsarray of User
pageinteger
pageSizeinteger
totalinteger
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

FieldTypeNotes
statusstringOne of ok.
databasestringOne of up, down.
Example
{
  "status": "ok",
  "database": "up"
}

ErrorResponse

Every error has this shape.

FieldTypeNotes
statusCodeinteger
errorstring
codestringWhat 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.
messagestring
issues optionalarray of objectFor 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."
    }
  ]
}