Sessions
Sessions are lobbies: a player opens one, friends join it, everyone readies up, and your game server takes it from there. The platform keeps the lobby; your servers host the match.
Switching it on
Switch the Sessions service on for your project in the console. Until you do, every /sessions route answers service-disabled. The environment's Sessions page lists its sessions, newest first, and can filter them by status.
The lifecycle
CONFIGURING ──(everyone present is ready)──> PREPARING_INSTANCE
│ your server reports
▼
AWAITING_PLAYERS ──> PLAYING ──> COMPLETE
(any of these can become ERROR)
| Status | Meaning | Moved there by |
|---|---|---|
CONFIGURING |
The lobby is open: players join, leave and ready up | Creating the session |
PREPARING_INSTANCE |
Everyone present is ready; your server should start the match | The last ready |
AWAITING_PLAYERS |
Your server is up and waiting for players to connect | Your server |
PLAYING |
The match is under way | Your server |
COMPLETE |
The match ended | Your server |
ERROR |
Something went wrong | Your server |
The lobby (player routes)
Every lobby route takes the player's access token.
| Route | Body | What it does |
|---|---|---|
POST /sessions |
{ gameMode, map, playerName?, uniqueNetId? } |
Opens a lobby with the caller as host. Answers 201 |
GET /sessions/:id |
Reads a lobby (a server key may too) | |
POST /sessions/:id/join |
{ playerName?, uniqueNetId? } |
Takes a seat |
POST /sessions/:id/leave |
none | Gives up the caller's seat. Answers 204 |
POST /sessions/:id/ready |
{ isReady } |
Marks the caller ready or not ready |
POST /sessions/:id/players/:playerId/kick |
none | The host removes a seated player |
POST /sessions/:id/players/:playerId/promote |
none | The host hands the host role to another seated player |
gameMode and map are your own words, 1 to 60 characters each; the platform stores them and gives them back. playerName is the name the seat shows (1 to 40 characters, filtered as a display name is); without it the seat uses the player's display name, or Player when they have none. uniqueNetId (up to 200 characters) is the player's id on your online subsystem; it is stored with the seat for your own use and is not returned in the session today.
A session is returned as:
{
"id": "0199a7d0-4f7a-7b02-a1c3-9e6f2b8d5c10",
"status": "CONFIGURING",
"gameMode": "coop",
"map": "harbour",
"conclusion": null,
"seats": 4,
"players": [
{
"playerId": "0199a7c3-0b2d-7e11-8c55-5f0e3d9a4b21",
"playerName": "Ada",
"isHost": true,
"isReady": false
},
{
"playerId": "0199a7c4-6e90-7a3f-b4d2-1c7e8f0a9b33",
"playerName": "Grace",
"isHost": false,
"isReady": false
}
],
"createdAt": "2026-09-29T12:05:00.000Z"
}
Seats are listed host first, then in the order players joined.
Rules
- A lobby has the seats its project gives it: 4 until an admin changes it on the project's page in the console, up to what the org's plan allows (8 on Free, 64 on Studio). Every session answers its
seats. Joining a full lobby is refused withconflict,details.limitsaying how many seats it has. Lowering the number leaves a fuller lobby its players; it takes nobody more. - A player joins by the session's id. There is no lobby browser: share the id however your game does (a join code your client shows, a friend invite, your own matchmaking).
- Joining, readying, kicking and promoting work only while the session is
CONFIGURING. Afterwards they answerconflict. - Only the host may kick or promote. A seated player who is not the host is refused with
forbidden. - When a player readies and everybody else seated is already ready, the session moves to
PREPARING_INSTANCE. There is no minimum head count: a host alone in a lobby who readies starts it. If your game needs more players, have your client wait before it offers Ready. - Leaving does not pass the host role on. A host who leaves while others are seated should promote somebody first.
- Only players of the same environment can be seated.
Clients hear about every change the moment it happens over the sessions socket: seats taken and given up, readies, kicks, promotions, the status moving, who is connected, and your game's own messages between seats. See Realtime. There is no need to poll; read the session with GET /sessions/:id when your client has no socket open.
Your server's part
Once a session reaches PREPARING_INSTANCE, the platform's work is done and yours begins: start or assign a match server, get the players connected, and report progress with your server key.
curl -X POST https://api.greenmindmedia.com/api/platform/v1/sessions/$SESSION_ID/status \
-H "Authorization: Bearer $GM_SERVER_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "PLAYING" }'
| Field | Rules |
|---|---|
status |
AWAITING_PLAYERS, PLAYING, COMPLETE or ERROR |
conclusion |
Optional, 1 to 60 characters, your own word for how it ended (victory, abandoned). Kept when the status is COMPLETE |
error |
Optional, up to 500 characters. Kept when the status is ERROR |
A session only moves forward:
| From | To |
|---|---|
PREPARING_INSTANCE |
AWAITING_PLAYERS, PLAYING, ERROR |
AWAITING_PLAYERS |
PLAYING, ERROR |
PLAYING |
COMPLETE, ERROR |
Any other move is refused with conflict, including any move out of CONFIGURING, which only the players' ready check makes. If two reports arrive at once, one succeeds and the other is refused with conflict: read the session and decide again.
How your server learns that a session is ready is up to you. Typically the host's client, on seeing PREPARING_INSTANCE (a session.status frame on the socket), asks your backend for a match server and passes the session id; your server then reads the session with GET /sessions/:id to see who is seated. Each report your server makes reaches every seat's socket as session.status.
Hosting
Today your servers host every match. The API a server calls does not assume where it runs, and hosting match servers for studios may come later.