> ## 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.

# POST /session/verify

> OTT를 검증하고 게임 세션을 생성합니다

<Badge color="green">POST</Badge> `/v1/game/session/verify`

PlayWave 런처에서 발급된 <Tooltip tip="One-Time Token — 1회용 UUID 토큰 (1분 TTL). 런처에서 게임 서버로 세션을 전달합니다">OTT</Tooltip>를 검증합니다. 유효한 경우 과금을 시작하고 게임 세션을 생성합니다.

## 요청

### Headers

<ParamField header="X-Api-Key" type="string" required>
  게임별 API Key.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `application/json`
</ParamField>

### Body

<ParamField body="ott" type="string" required>
  LaunchData에서 추출한 <Tooltip tip="One-Time Token — Roblox GetJoinData().LaunchData에서 추출">OTT</Tooltip> UUID.
</ParamField>

<ParamField body="provider_user_id" type="string" required>
  Roblox Player UserId를 문자열로 변환한 값.
</ParamField>

```json theme={null}
{
  "ott": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "provider_user_id": "123456789"
}
```

## 응답

### 성공 — <Badge color="green">200</Badge>

```json theme={null}
{
  "success": true,
  "request_id": "req_abc123",
  "data": {
    "is_valid": true,
    "game_session_id": "gs_550e8400-e29b-41d4-a716-446655440000",
    "is_pc_cafe": true
  }
}
```

<ResponseField name="is_valid" type="boolean" required>
  검증 성공 여부.
</ResponseField>

<ResponseField name="game_session_id" type="string" required>
  게임 세션 ID — 하트비트/종료 호출에 사용합니다.
</ResponseField>

<ResponseField name="is_pc_cafe" type="boolean" required>
  인증된 PC방 여부.
</ResponseField>

### 검증 실패 — <Badge color="green">200</Badge>

비즈니스 로직 실패도 HTTP 200으로 반환됩니다. 반드시 `is_valid` 값으로 분기하세요.

```json theme={null}
{
  "success": true,
  "request_id": "req_abc123",
  "data": {
    "is_valid": false,
    "reason": "OTT_EXPIRED"
  }
}
```

| reason             | 설명                                                                     |
| ------------------ | ---------------------------------------------------------------------- |
| `OTT_EXPIRED`      | OTT 만료 (발급 후 1분 초과)                                                    |
| `OTT_ALREADY_USED` | OTT 이미 사용됨                                                             |
| `GAME_MISMATCH`    | OTT의 게임과 API Key의 게임 불일치                                               |
| `NOT_CHARGEABLE`   | 과금 불가 (<Tooltip tip="PC방 플레이 시간 과금에 사용되는 가상 화폐">G-coin</Tooltip> 부족 등) |

### 에러

| HTTP                              | 코드                | 설명                |
| --------------------------------- | ----------------- | ----------------- |
| <Badge color="yellow">400</Badge> | `BAD_REQUEST`     | 필수 필드 누락 또는 형식 오류 |
| <Badge color="yellow">401</Badge> | `INVALID_API_KEY` | API Key 무효        |

## Luau 예제

```lua theme={null}
local function verifySession(player)
    local joinData = player:GetJoinData()
    local ott = joinData.LaunchData

    if not ott or ott == "" then
        return nil
    end

    local success, response = pcall(function()
        return HttpService:RequestAsync({
            Url = API_URL .. "/game/session/verify",
            Method = "POST",
            Headers = {
                ["X-Api-Key"] = API_KEY,
                ["Content-Type"] = "application/json",
            },
            Body = HttpService:JSONEncode({
                ott = ott,
                provider_user_id = tostring(player.UserId),
            }),
        })
    end)

    if not success or response.StatusCode ~= 200 then
        return nil
    end

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