Error response format
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "API Key is invalid or inactive",
"timestamp": "2026-03-06T12:00:00.000Z"
}
}
HTTP error codes
| Code | HTTP | Description |
|---|---|---|
BAD_REQUEST | 400 | Request body validation failed (missing required fields, format error) |
INVALID_API_KEY | 401 | API Key missing, invalid, or inactive game |
RATE_LIMITED | 429 | Request rate limit exceeded |
SESSION_NOT_FOUND | 404 | Game session not found (expired/deleted) |
SESSION_ENDED | 410 | Game session already terminated |
SESSION_ENDING | 410 | Game session termination in progress (grace period) |
ALREADY_ENDED | 409 | Duplicate termination attempt on already-ended session |
INTERNAL_ERROR | 500 | Internal server error |
Business status codes
Returned as HTTP 200, delivered via thereason or result field in the response body.
verify response — reason
| reason | Description | Game server action |
|---|---|---|
OTT_EXPIRED | OTT expired (over 1 min) | Tell user to relaunch from the launcher |
OTT_ALREADY_USED | OTT already consumed | Prevent duplicate connections — kick user |
GAME_MISMATCH | OTT game / API Key game mismatch | Invalid OTT — kick user |
NOT_CHARGEABLE | Billing not possible (insufficient G-coin) | Tell user to recharge G-coin |
heartbeat response — result
| result | Description | Game server 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 |
Error handling patterns
Retryable errors
-- Network errors and 5xx errors are retried on the next heartbeat cycle
if err == "NETWORK_ERROR" or string.sub(err, 1, 5) == "HTTP_5" then
warn("[Playwave] Temporary error, will retry:", err)
-- Auto-retry on next loop cycle
end
Session-lost errors
-- 404/410 errors mean the session is gone — stop heartbeat + kick user
if err == "HTTP_404" or err == "HTTP_410" then
activeSessions[userId] = nil
local player = Players:GetPlayerByUserId(userId)
if player then
player:Kick("PlayWave session expired")
end
end
Ignorable errors
-- 404/409 on session end means already cleaned up — safe to ignore
if err == "HTTP_404" or err == "HTTP_409" then
-- Normal operation — session already cleaned up
return
end