Skip to main content
PATCH /v1/game/session/heartbeat Reports that the game session is still active. Must be called every 2 minutes (120 seconds). If heartbeats stop, the session is automatically deleted when the (4 min) expires.

Request

Headers

X-Api-Key
string
required
Per-game API Key.
Content-Type
string
required
application/json

Body

game_session_id
string
required
Game session ID returned by the verify endpoint.
provider_user_id
string
required
Roblox Player UserId (string).
{
  "game_session_id": "gs_550e8400-e29b-41d4-a716-446655440000",
  "provider_user_id": "123456789"
}

Response

Success — 200

{
  "success": true,
  "request_id": "req_abc123",
  "data": {
    "result": "OK",
    "next_heartbeat_in": 120,
    "play_duration_sec": 1800
  }
}
result
string
required
Session status. One of OK, CHARGE_EXHAUSTED, or SESSION_REPLACED.
next_heartbeat_in
integer
required
Recommended wait time until next heartbeat (seconds). Default 120.
play_duration_sec
integer
required
Server-side cumulative play time (seconds).

result values

resultDescriptionAction
OKNormalSend next heartbeat after next_heartbeat_in
CHARGE_EXHAUSTED depletedNotify user. Server auto-terminates after 2 min grace
SESSION_REPLACEDAnother game session started on the same PCStop heartbeat. Do not call session end — the server already terminated this session
Launcher heartbeat timeout: The server also checks the launcher’s heartbeat when processing game server heartbeats. If the launcher hasn’t sent a heartbeat for over 4 minutes, the server considers the launcher dead and terminates the game session. In this case, the heartbeat returns HTTP 410 SESSION_ENDED. This can happen when the PlayWave launcher crashes or is force-closed while the game is still running.

Errors

HTTPCodeDescriptionAction
404SESSION_NOT_FOUNDSession not found (expired/deleted)Stop heartbeat, kick user
410SESSION_ENDEDSession already endedStop heartbeat, kick user
410SESSION_ENDINGTermination in progressStop heartbeat, kick user

Luau example

local function sendHeartbeat(gameSessionId, providerUserId)
    local success, response = pcall(function()
        return HttpService:RequestAsync({
            Url = API_URL .. "/game/session/heartbeat",
            Method = "PATCH",
            Headers = {
                ["X-Api-Key"] = API_KEY,
                ["Content-Type"] = "application/json",
            },
            Body = HttpService:JSONEncode({
                game_session_id = gameSessionId,
                provider_user_id = providerUserId,
            }),
        })
    end)

    if not success then
        warn("[Playwave] Heartbeat failed:", response)
        return nil, "NETWORK_ERROR"
    end

    if response.StatusCode == 404 or response.StatusCode == 410 then
        return nil, "SESSION_LOST"
    end

    local body = HttpService:JSONDecode(response.Body)
    return body.data, nil
end