Session states
A game session transitions through the following states.
| State | Description |
|---|
NONE | Before user connects. Waiting for LaunchData check |
VERIFYING | OTT verification API call in progress |
ACTIVE | Verification succeeded. Heartbeat loop running |
ENDING | Session end API call in progress |
ENDED | Session terminated |
Session creation
When a user connects through the PlayWave launcher, LaunchData contains the OTT.
-- Extract OTT on the server
local joinData = player:GetJoinData()
local ott = joinData.LaunchData -- OTT UUID string
If an OTT is present, call POST /v1/game/session/verify to verify it. On success, the game_session_id is returned and the session becomes ACTIVE.
Users connecting without the PlayWave launcher will have empty LaunchData. In this case, verification is skipped and the user is treated as a normal player.
Heartbeat
Once the session is ACTIVE, heartbeats are sent every 2 minutes (120 seconds).
-- Heartbeat loop
while activeSessions[userId] do
task.wait(120) -- 2 min wait
apiRequest("PATCH", "/game/session/heartbeat", {
game_session_id = gameSessionId,
provider_user_id = providerUserId,
})
end
Heartbeat response handling
| result | Meaning | Action |
|---|
OK | Normal | Wait until next heartbeat |
CHARGE_EXHAUSTED | G-coin depleted | Notify user. Server auto-terminates after 2 min grace period |
SESSION_REPLACED | Another session started on same PC | Stop heartbeat. Do not call session end |
Heartbeat error handling
| HTTP Status | Meaning | Action |
|---|
| 404 | Session not found (expired/deleted) | Stop heartbeat, kick user |
| 410 | Session already ended | Stop heartbeat, kick user |
| 5xx | Server error | Retry on next cycle |
If no heartbeat is received for 4 minutes or more, the server automatically terminates the session. Maintain the 2-minute interval.
Session termination
Sessions can end in 6 ways.
1. Normal exit (normal)
When a user leaves the game, the session end API is called in the PlayerRemoving event.
Players.PlayerRemoving:Connect(function(player)
endPlayerSession(player.UserId)
end)
2. Server shutdown (BindToClose)
When the Roblox server shuts down, all active sessions are cleaned up.
game:BindToClose(function()
for userId in pairs(activeSessions) do
endPlayerSession(userId)
end
end)
3. Heartbeat timeout (heartbeat_timeout)
If no heartbeat is received for 4 minutes, the server automatically terminates the session. This covers cases like PC power-off or network failure.
4. Session replace (session_replace)
If a different game is launched from the same PC, the existing game session is auto-terminated and a new session is created. The heartbeat for the old session will return SESSION_REPLACED.
5. Launcher heartbeat timeout
The server checks launcher liveness during game server heartbeats. If the launcher hasn’t sent a heartbeat for over 4 minutes, the server terminates the game session (returns HTTP 410). This happens when the launcher crashes or is force-closed while the game is still running.
6. G-coin exhausted (charge_exhausted)
When CHARGE_EXHAUSTED is received in a heartbeat response, the server auto-terminates the session after a 2-minute grace period.
Timeline examples
Normal exit
Abnormal exit