Skip to main content

Session states

A game session transitions through the following states.
StateDescription
NONEBefore user connects. Waiting for LaunchData check
VERIFYINGOTT verification API call in progress
ACTIVEVerification succeeded. Heartbeat loop running
ENDINGSession end API call in progress
ENDEDSession 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

resultMeaningAction
OKNormalWait until next heartbeat
CHARGE_EXHAUSTEDG-coin depletedNotify user. Server auto-terminates after 2 min grace period
SESSION_REPLACEDAnother session started on same PCStop heartbeat. Do not call session end

Heartbeat error handling

HTTP StatusMeaningAction
404Session not found (expired/deleted)Stop heartbeat, kick user
410Session already endedStop heartbeat, kick user
5xxServer errorRetry 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