Sessions
Create a session
/v1/sessionsCreates a new session for one of the eight supported games. Returns a short-lived session token for your client.
Body parameters
| Field | Type | Description | |
|---|---|---|---|
game | string | required | chess · checkers · connect4 · tictactoe · subway-runner · pool · chkobe · archery |
mode | string | optional | Defaults to live for a live key, test for a test key. Test keys cannot request live. |
matchType | string | optional | matchmaking (default) · private · bot · hosted |
players | array | live / test | Array of { id, displayName }. Required for every mode except training. |
playerCount | number | training only | How many anonymous players to generate (max 2). |
platform | string | optional | android or ios — triggers a device integrity check if a credential exists. |
integrityToken | string | optional | Attestation token from the platform's integrity SDK. |
subway-runner is single-player and only accepts matchType: "bot" — it will reject any other match type with 400.Response — 201
| Field | Type | Description |
|---|---|---|
sessionId | string | Unique session identifier. |
sessionToken | string (JWT) | Hand this to the client. Expires in expiresIn seconds (300). |
roomCode | string | null | Present only for private / hosted match types — share it with the second player. |
theme | object | Your tenant’s embed theme (colours, logo, font) so the client can render on-brand. |
webhooksEnabled | boolean | true only when mode is live. |
Match types
matchmaking
Default. The player is placed in your tenant's queue and paired by rating when an opponent is available.
bot
Pass one player; the second seat is filled by a bot, either immediately or after a matchmaking fallback delay — see Matchmaking fallback.
private
Pass the host only. A roomCode is returned; the second player calls /v1/sessions/join with that code.
hosted
Same shape as private, intended for spectated or tournament-style rooms hosted by your own backend.
Retrieve a session
/v1/sessions/:id?game=chessFetches a single session, including its result once the game has ended. Requires the same tenant that created it.
| Field | Location | Description | |
|---|---|---|---|
id | path | required | The sessionId from creation. |
game | query | required | Sessions are sharded per game table — this tells the API where to look. |
Response — 200
{
"id": "a1b2c3d4-...",
"tenantId": "t_9c21...",
"game": "chess",
"mode": "live",
"matchType": "matchmaking",
"status": "ended", // pending | active | ended
"players": [ /* SessionPlayer[] */ ],
"result": { /* GameResult, see Games Reference */ },
"createdAt": "2026-06-02T14:00:00Z",
"endedAt": "2026-06-02T14:11:32Z"
}Join a private room
/v1/sessions/joinAdds a second player to a private or hosted session using its room code, and returns a fresh session token for the joiner.
| Field | Type | Description | |
|---|---|---|---|
roomCode | string | required | Returned from session creation. |
game | string | required | Must match the room's game. |
player.id | string | required | Joining player's own user ID. |
player.displayName | string | optional | Defaults to player.id if omitted. |
A player.joined webhook fires (live mode only) and the response mirrors the session-creation shape, with the updated players array.
Validate a token
/v1/sessions/validate?token=…Unauthenticated lookup used by embed clients to confirm session status directly from a (possibly expired) session token — no API key needed, since the token itself proves knowledge of the session.
{
"status": "ended",
"game": "chess",
"result": { /* GameResult */ },
"fen": "rnbqkb1r/pp3ppp/..." // chess only, derived from the stored PGN
}The fen field is chess-specific — if a stored FEN isn't available, it's reconstructed on the fly from the session's PGN.