Skip to content
Auth, sessions and billing are live

An API to practise on.
Not another mock.

A sandbox for learning HTTP and testing clients against something real: genuine status codes, genuine validation errors, genuine token expiry. Authentication and sessions are the first surface — more is on the way.

auth.public.login()

POST /api/auth/public/login
POST /api/auth/public/login HTTP/1.1
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "correct-horse-battery-staple",
  "device": { "deviceId": "Chrome · macOS · a1b2c3d4" }
}
200 OK — AuthResponse
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "accessExpiresIn": 900,
  "refreshExpiresIn": 2592000
}
Try it in Swagger UI(opens in a new tab)
19
Live endpoints
2
Verification flows
0
Setup steps

api.auth

A sandbox that behaves like production

The parts a mock server skips, and the ones worth practising against.

The full token dance

Short-lived access tokens and single-use refresh tokens that really rotate. Watch one expire.

Two verification paths

One email carries both a six-digit code and a confirmation link. Exercise either.

Sessions you can break

List active devices, then revoke one out from under your own client and see what happens.

Honest failures

400 with per-field detail, 409 on a taken email, 429 when you push too hard. Not a wall of 200s.

auth.public.register()

Three calls to authenticated

From an empty project to a bearer token you can actually send.

01

Register

Post an email, a password and a device id. You get back a registration id.

POST /api/auth/public/register
POST /api/auth/public/register HTTP/1.1
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "correct-horse-battery-staple",
  "device": { "deviceId": "Chrome · macOS · a1b2c3d4" }
}
202 Accepted — RegisterResponse
{
  "registrationId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
  "expiresIn": 900
}
02

Verify

Enter the code or open the link. The API answers with a token pair.

POST /api/auth/public/verify/code
POST /api/auth/public/verify/code HTTP/1.1
Content-Type: application/json

{
  "registrationId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
  "code": "042931"
}
03

Call the API

Send the access token as a bearer. Refresh it before it expires.

GET /api/auth/sessions
curl https://staging.apidemo.app/api/auth/sessions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1…"

auth.sessions()

Every device, revocable

One call lists everywhere the account is signed in. Another takes any of them away.

200 OK — SessionView[]
[
  {
    "sessionId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
    "current": true,
    "createdAt": "2026-08-19T09:12:00Z",
    "lastSeenAt": "2026-08-21T07:40:00Z",
    "deviceId": "Chrome · macOS · a1b2c3d4"
  },
  {
    "sessionId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "current": false,
    "createdAt": "2026-08-11T18:03:00Z",
    "lastSeenAt": "2026-08-20T21:15:00Z",
    "deviceId": "Safari · iOS · 5f4dcc3b"
  }
]

auth.public.register()

Point your client at a real API

Create a test account and make your first authenticated call in a couple of minutes.