> ## Documentation Index
> Fetch the complete documentation index at: https://playwave.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Error codes

> Game Server API error codes and how to handle them

## Error response format

```json theme={null}
{
  "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 the `reason` 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

```lua theme={null}
-- 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

```lua theme={null}
-- 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

```lua theme={null}
-- 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
```
