﻿# Operator Integration Guide

Detailed description of the endpoints an **operator / terminal** uses to integrate with InfinityPlay, and the **wallet callbacks** the platform will call back into the operator when running in seamless mode.

> Source of truth in code: `Api.InfinityPlay/Casino/CasinoApiController.cs`, `GameGlobal.GameApi/ApiConnector/Real/RealApiAdapter.cs`, DTOs under `Global.ShareFunction/Model/FromTerminal` and `FromProvider`.

---

## 1. Integration model (two directions)

```
┌────────────────────┐         POST /api/casinoapi         ┌──────────────────┐
│  Operator / Casino │  ─────────────────────────────────► │  Api.InfinityPlay    │
│  (your backend)    │         method = GetGameUrl, …      │  (platform API)  │
└────────────────────┘                                     └────────┬─────────┘
         ▲                                                          │
         │  POST {your wallet endpoint}                             │ launch
         │  method = GetBalance / ChangeBalance                     ▼
         │                                                 ┌──────────────────┐
         └─────────────────────────────────────────────────│  Game host       │
                    (seamless mode only)                   │  EGT/HS/PP/…     │
                                                           └──────────────────┘
```

| Direction | Who calls whom | Purpose |
|-----------|----------------|---------|
| **A. Casino API** | Operator → Platform | Launch games, users, catalog, reports, free rounds, RTP, etc. |
| **B. Wallet API** | Platform → Operator | Read balance / debit / credit / cancel during play (**seamless**) |

There is also an internal-style game-host API (`POST /api/real`) used by platform tooling and some flows; operators normally integrate via **A + B**, not `/api/real`.

---

## 2. Casino API (Operator → Platform)

### 2.1 Endpoint

| Item | Value |
|------|--------|
| **URL** | `POST https://{api-domain}/api/casinoapi` |
| **Content-Type** | `application/json` |
| **Dispatch** | Single URL; action selected by JSON field `method` |

Production validates that the HTTP `Host` matches the agent’s configured `ApiDomain` (skipped in test mode).

### 2.2 Common request envelope

Every Casino API call includes:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `method` | string | yes | API method name (see catalog below) |
| `token` | string | yes | Agent API token (from platform backoffice / Agents table) |
| `agentCode` | string | yes | Must match the agent that owns `token` |

Invalid / empty token → `status = 3` and the client IP may be blocked.

### 2.3 Common response envelope

| Field | Type | Description |
|-------|------|-------------|
| `status` | int | `0` = success; otherwise error code (see §5) |
| `msg` | string | Human-readable message |
| `errorId` | long | Optional platform error id for support |

Method-specific fields are returned **alongside** this envelope on success.

---

## 3. Wallet modes

Configured per agent (`Agent.Mode`):

| Mode | Value | Operator must… | Notes |
|------|-------|----------------|-------|
| **Seamless** | `1` | Implement **GetBalance** + **ChangeBalance** on your wallet URL | Platform holds little/no cash; every spin hits your wallet |
| **Transfer** | `2` | Use **Deposit / Withdraw / WithdrawAll** on Casino API | Platform holds user balance; no spin-time wallet callbacks |

- Seamless agents: `CreateUser` is optional — `GetGameUrl` can auto-create the user.
- Transfer agents: user must exist before launch; auto-create on `GetGameUrl` is rejected.

---

## 4. Typical operator flows

### 4.1 Seamless launch

1. (Optional) `CreateUser`
2. `GetVendorGames` / `GetVendors` for lobby
3. `GetGameUrl` with `userCode`, `vendorCode`, `gameCode`, `currencyCode`, …
4. Open returned `launchUrl` in browser / WebView
5. During play, platform calls your wallet: `GetBalance`, `ChangeBalance` (debit/credit/cancel)

### 4.2 Transfer launch

1. `CreateUser`
2. `Deposit` (move money from agent pool → user)
3. `GetGameUrl`
4. After session: `Withdraw` or `WithdrawAll`

---

## 5. Status / error codes

From `P2TErrorCode` (Casino API responses):

| status | Name | Meaning |
|--------|------|---------|
| 0 | Success | OK |
| 1 | Internal_Error | Unexpected server error |
| 2 | Invalid_Action | Bad action / amount |
| 3 | Invalid_Agent | Bad token, blocked agent, wrong mode/type |
| 4 | Block_Agent | Agent blocked |
| 5 | Invalid_User | User missing / invalid |
| 6 | Block_User | User blocked |
| 7 | Duplicate_User | User already exists |
| 8 | Insufficient_Money | User or agent balance too low |
| 12 | Invalid_Vendor | Unknown / disabled vendor or routing |
| 13 | Invalid_Parameter | Missing/invalid fields |
| 14 | Network_Error | Downstream network failure |
| 15 | Maintenancing | Vendor under maintenance |
| 18 | Invalid_Wager | Wager not found / invalid |
| 20 | Invalid_Time | Time range invalid |
| 21 | Duplicate_RequestKey | Idempotent transfer key already used |
| 22 | Timeout_Error | Request timed out |
| 23 | GetBalance_Fail | Seamless balance fetch failed |
| 24 | ProviderInMaintenance | Provider maintenance |
| 25 | Invalid_PostResult | Downstream returned bad payload |

---

## 6. Vendor codes (game brands)

Use these as `vendorCode` when launching or listing games:

| vendorCode | Brand |
|------------|--------|
| `slot-egt` | EGT |
| `slot-egt-vip` | EGT VIP |
| `slot-hacksaw` | Hacksaw |
| `slot-pragmatic` | Pragmatic Play |

`gameCode` is brand-specific (e.g. Pragmatic `vs20olympgate`, Hacksaw numeric/string ids).

---

## 7. Casino API method catalog

All methods: `POST /api/casinoapi` with the fields below **plus** `method`, `token`, `agentCode`.

---

### 7.1 Users

#### `CreateUser`

Create a player under the agent.

**Request**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `userCode` | string | yes | Unique player id in your system |
| `nickName` | string | no | Stored as user variable |
| `password` | string | no | Stored as user variable (if used by site flows) |

**Success response:** `status=0` (empty body extras).

#### `DeleteUser`

Removes the user. Not allowed for circulation agents (`Type = 2`).

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |

#### `ChangeUserPassword`

Updates nickname/password variables for an existing user.

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |
| `nickName` | string | no |
| `password` | string | no |

#### `GetUserInfo`

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |

**Success extras**

```json
{
  "status": 0,
  "users": [
    {
      "userCode": "player1",
      "balances": { "USD": 100.5 }
    }
  ]
}
```

#### `GetAgentInfo`

No extra request fields. Returns agent profile / holdings summary for the authenticated agent.

---

### 7.2 Transfer wallet (transfer mode only)

#### `Deposit` / `Withdraw` / `WithdrawAll`

Same request shape (`Deposit_Request`). Rejected if agent is seamless.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `userCode` | string | yes | Player |
| `currencyCode` | string | no | Defaults to agent currency |
| `amount` | number | yes* | Absolute amount; ignored for `WithdrawAll` |
| `requestKey` | string | no | Idempotency key; duplicate → status `21` |

\* For `WithdrawAll`, amount is not used; full user balance is withdrawn.

**Success extras**

| Field | Type | Description |
|-------|------|-------------|
| `prevBalance` | number | User balance before |
| `balance` | number | User balance after |

---

### 7.3 Catalog & launch

#### `GetVendors`

Lists vendors enabled for the agent.

**Success extras**

```json
{
  "vendors": [
    {
      "vendorCode": "slot-pragmatic",
      "vendorName": "Pragmatic",
      "gameType": 1,
      "logoUrl": "https://…"
    }
  ]
}
```

#### `GetVendorGames`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `vendorCode` | string | yes | e.g. `slot-hacksaw` |
| `gameType` | byte | no | Filter |
| `userCode` | string | no | Routing context |
| `language` | string | no | Localization hint |

**Success extras**

```json
{
  "vendorGames": [
    {
      "gameType": 1,
      "gameCode": "vs20olympgate",
      "gameName": "Gates of Olympus",
      "imageUrl": "https://…"
    }
  ]
}
```

#### `GetGameUrl` ⭐ primary launch method

Creates/updates session and returns a browser launch URL.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `userCode` | string | yes | Player id |
| `vendorCode` | string | yes | See §6 |
| `gameCode` | string | yes | Game symbol / id |
| `currencyCode` | string | recommended | ISO currency |
| `language` | string | no | e.g. `en`, `ko` |
| `nickName` | string | no | Display name |
| `userBalance` | number | no | Hint / seed depending on mode |
| `betLimit` | string | no | Limit profile if used |
| `homeUrl` | string | no | Exit / lobby URL for client |
| `channel` | string | no | Default `desktop` |
| `playMode` | string | no | Play mode flag |
| `lowRtp` / `highRtp` | number | no | Per-session RTP band |
| `liveRatio` / `liveMode` / `initLiveCount` | number/int | no | Live / call controls |
| `freeRounds` | string | no | Free-round payload if used |
| `isTest` | bool | no | Test flag |

**Success extras**

| Field | Type | Description |
|-------|------|-------------|
| `launchUrl` | string | Open this URL for the player |

**Notes**

- Issues a **new session token** for the game host.
- On seamless launch, platform typically calls operator **GetBalance** first; failure → status `23`.
- Vendor must be routed for this agent/user/game (`AgentVendorProvider` path).

---

### 7.4 Wagers & reports

#### `GetWagerInfo`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `wagerId` | long | one of | Internal wager id |
| `wagerCode` | string | one of | External / bridge code |

Returns a `P2TWagerInfo`-shaped object (see fields below).

#### `ReportById`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `startWagerId` | long | yes | Fetch wagers after this id |
| `count` | int | yes | Page size |

**Success extras:** `wagers[]`, `lastWagerId`.

#### `ReportByDate`

| Field | Type | Required |
|-------|------|----------|
| `startDate` | datetime | yes |
| `endDate` | datetime | yes |

**Success extras:** `wagers[]`.

#### Wager object (`P2TWagerInfo`)

| Field | Type | Description |
|-------|------|-------------|
| `wagerCode` | string | Code |
| `wagerId` | long? | Id |
| `userCode` | string | Player |
| `vendorCode` | string | Brand |
| `gameCode` / `gameName` | string | Game |
| `gameRoundId` | string | Round id |
| `betAmount` / `payoutAmount` | number | Stake / win |
| `currency` | string | Currency |
| `createdOn` / `modifiedOn` / `settlementOn` | datetime | Timestamps |
| `isFinished` | bool | Settled |
| `status` | byte | Internal status |
| `gameType` | byte? | Type |
| `beforeBalance` / `afterBalance` | number? | Balances |
| `detail` | string | Extra JSON/text |

#### `GetDetailUrl`

Returns a URL to open round detail UI.

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | often |
| `vendorCode` | string | often |
| `gameRoundId` | string | often |
| `wagerCode` / `wagerId` | string/long | often |
| `language` / `currencyCode` | string | no |

**Success extras:** `detailUrl`.

---

### 7.5 Free rounds

#### `ApplyFreeRound`

Awards promotional free spins. The player sees the native in-game FS dialog (same UI as bonus buy). **Pragmatic:** only games that have a bonus-buy feature (`GetFreeRoundSupportMap`). Stake is coin × lines.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `userCode` | string | yes | Player |
| `vendorCode` | string | yes | Brand |
| `gameCode` | string | yes | Game |
| `currencyCode` | string | yes | Currency |
| `betAmount` | decimal | yes | Stake per free spin (total bet) |
| `spinCount` | int | yes | Number of free spins |
| `expireHours` | double | yes | TTL in hours |

After apply, open `GetGameUrl` so the player starts the awarded feature. Wallet: no per-spin debit; one credit when the feature package finishes (see §8.5).

#### `CancelFreeRound`

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |
| `vendorCode` | string | yes |
| `gameCode` | string | yes |
| `currencyCode` | string | yes |

#### `GetFreeRoundList`

Returns current free-round inventory for the scoped user/game context.

**Success extras:** `freeRounds` (list of decimals / amounts depending on brand mapping).

#### `GetFreeRoundSupportMap`

**Success extras:** `gameCodes[]` — games that support promotional free rounds for the vendor context.

---

### 7.6 RTP / live call controls

#### `ChangeUserRtp`

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |
| `vendorCode` | string | yes |
| `currencyCode` | string | yes |
| `gameCode` | string | yes |
| `lowRtp` | number | yes |
| `highRtp` | number | yes |

#### `ChangeAgentRtp`

Agent-level RTP defaults (request fields mirror agent RTP settings; see `ChangeAgentRtp_Request`).

#### `CallApply`

Queue a “call” / forced outcome profile for a player.

| Field | Type | Required |
|-------|------|----------|
| `userCode` | string | yes |
| `currencyCode` | string | yes |
| `vendorCode` | string | yes |
| `gameCode` | string | yes |
| `callRtp` | decimal | yes |
| `betAmount` | decimal | yes |
| `callType` | string | yes |

#### `CallCancel`

Cancel a pending call (see `CallCancel_Request`).

#### `GetCallList` / `GetCallHistory`

Inspect pending and historical calls (`vendorCode`, `gameCode`, `callType` filters on list).

---

### 7.7 Game settings & variables

Used for per-user / per-game configuration pushed into game hosts.

#### `GetGameSetting` / `SetGameSetting` / (remove via related methods)

`SetGameSetting` / variable writes use:

| Field | Type | Description |
|-------|------|-------------|
| `userCode` | string | Scope |
| `vendorCode` | string | Brand |
| `gameCode` | string | Game |
| `currencyCode` | string | Currency |
| `category` | string | Setting group |
| `key` | string | Setting name |
| `value` | string | Setting value |

#### `GetGameVariable` / `SetGameVariable` / `GetGameVariables`

Same scoping idea as settings; variables are key/value bags used by engines (nickname, free-round state, etc.).

---

### 7.8 Ops / misc

#### `GetCurrentPlayers`

No extra fields. Returns online/session players:

```json
{
  "playerInfos": [
    {
      "userCode": "p1",
      "nickName": "…",
      "currencyCode": "USD",
      "vendorCode": "slot-pragmatic",
      "gameCode": "vs20olympgate",
      "betAmount": 1.0,
      "balance": 99.0,
      "lowRtp": 96,
      "highRtp": 97
    }
  ]
}
```

#### `EventPayment`

| Field | Type | Required |
|-------|------|----------|
| `eventId` | long | yes |

Processes a configured event payout for the agent/user context.

---

## 8. Wallet API (Platform → Operator) — seamless

When the agent is **seamless**, each game host is configured with an operator wallet URL (`Api.Endpoint`) and token (`Api.Token`). The platform **POSTs JSON** to that URL.

You must implement the same style of dispatcher: one URL, `method` field.

### 8.1 Common wallet request fields

From `Provider_Request` / `Request`:

| Field | Type | Description |
|-------|------|-------------|
| `method` | string | `GetBalance` or `ChangeBalance` |
| `token` | string | Token you issued / that is stored on the platform API row |
| `userCode` | string | Player id |
| `vendorCode` | string | Brand code (e.g. `slot-pragmatic`) |

### 8.2 Common wallet response

| Field | Type | Description |
|-------|------|-------------|
| `status` | int | `0` = success |
| `msg` | string | Message |
| `balance` | number | **Current balance after the operation** (required on success) |
| `balanceTime` | datetime? | Optional timestamp |

`ChangeBalance` may also echo `wagerId` / `transId` if you return them; the platform primarily requires `status` + `balance`.

---

### 8.3 `GetBalance`

Called on launch (and whenever the engine needs a fresh balance).

**Request extras**

| Field | Type | Description |
|-------|------|-------------|
| `currencyCode` | string | Currency |

**Example request**

```json
{
  "method": "GetBalance",
  "token": "YOUR_WALLET_TOKEN",
  "userCode": "player1",
  "vendorCode": "slot-pragmatic",
  "currencyCode": "USD"
}
```

**Example success**

```json
{
  "status": 0,
  "msg": "OK",
  "balance": 1250.50
}
```

---

### 8.4 `ChangeBalance`

Called for bet debit, win credit, cancel/rollback, bonus, etc.

**Request extras**

| Field | Type | Description |
|-------|------|-------------|
| `txnCode` | string | Unique transaction id (idempotency key) — **must treat duplicates safely** |
| `pairCode` | string | Optional pair reference |
| `gameCode` | string | Game |
| `gameRoundId` | string | Round id |
| `amount` | number | Signed money movement for this txn |
| `createdOn` | datetime | UTC time from platform |
| `txnType` | byte | See txn types below |
| `debitCreditPair` | bool | Pairing flag |
| `wagerId` | long | Platform wager id |
| `detail` | string | Extra detail |
| `currencyCode` | string | Currency |
| `isReal` | bool | Real money vs promo |
| `isFreeRound` | bool | Free-round spin |
| `freeRoundCount` | int | Remaining / related count |
| `betAmount` | number | Often `-1` if not filled by adapter |
| `payoutAmount` | number | Often `-1` if not filled |
| `bridgeBetAmount` | number | Bridged bet amount |
| `bridgePayoutAmount` | number | Bridged payout amount |
| `wagerCode` | string | Optional wager code |
| `isFinished` | bool | Round finished after this txn |
| `providerPath` | string | Internal routing path |

**Txn types (`TxnType`)**

| Value | Name | Typical meaning |
|-------|------|-----------------|
| 0 | `TT_Debit` | Bet / take money |
| 1 | `TT_Credit` | Win / return money |
| 2 | `TT_Cancel` | Cancel pending debit |
| 3 | `TT_Rollback` | Rollback |
| 4 | `TT_Buyin` | Buy-in |
| 5 | `TT_Buyout` | Buy-out |
| 6 | `TT_Pushbet` | Push bet |
| 7 | `TT_Bonus` | Bonus |
| 8 | `TT_Jackpot` | Jackpot |
| 9 | `TT_Other` | Other |
| 99 | `TT_Match` | Match |

**Example debit**

```json
{
  "method": "ChangeBalance",
  "token": "YOUR_WALLET_TOKEN",
  "userCode": "player1",
  "vendorCode": "slot-pragmatic",
  "currencyCode": "USD",
  "txnType": 0,
  "txnCode": "slot-pragmatic_12345_987654_0_1710000000000",
  "wagerId": 12345,
  "gameCode": "vs20olympgate",
  "gameRoundId": "987654",
  "amount": -1.0,
  "isFreeRound": false,
  "isFinished": false,
  "createdOn": "2026-08-12T18:00:00Z"
}
```

**Example success**

```json
{
  "status": 0,
  "msg": "OK",
  "balance": 1249.50
}
```

### 8.5 Wallet implementation requirements

1. **Authenticate** `token` on every call.
2. **Idempotent** `ChangeBalance` on `txnCode` (retries happen; timeout is ~3s on send).
3. Always return **post-txn `balance`** on success.
4. Reject with non-zero `status` on insufficient funds / unknown user (platform will fail the spin).
5. Free-round **debit** is skipped on the platform for promotional FS (`isFreeRound=true` on the wager). Do **not** expect a `txnType=0` per free spin.
6. **Credit is sent once when the free-spin package finishes** (`txnType=1`, `isFinished=true`), not on every winning free spin. This matches in-game bonus-buy FS. If the player closes mid-feature, the pending pack win is stored and paid on reconnect or when the unfinished round is closed.
7. Bonus-buy (paid `pur=`) **does** debit the buy cost immediately (`txnType=0`, `isFinished=false`), then credits the feature win once at the end.

---

## 9. Optional: Game-host Real Casino API

Each game host also exposes:

`POST https://{game-host}/api/real`

Authenticated with the **game API token** (not the operator agent token). Methods overlap Casino API for in-brand ops (`GetGameUrl`, free rounds, RTP, settings, …).

Operators integrating a full casino should prefer **`/api/casinoapi`**. Use `/api/real` only if you are talking to a single brand host directly (ops / special tooling).

---

## 10. Minimal integration checklist (go-live)

### Operator side

- [ ] Agent created with `agentCode` + `token` + correct `ApiDomain`
- [ ] Mode chosen: Seamless (`1`) or Transfer (`2`)
- [ ] Vendors enabled and games visible via `GetVendorGames`
- [ ] **If seamless:** public HTTPS wallet URL implementing `GetBalance` + `ChangeBalance`, token configured on platform `Api.Endpoint` / `Api.Token`
- [ ] **If transfer:** Deposit/Withdraw working; agent holding funded
- [ ] Launch path verified: `GetGameUrl` → open `launchUrl` → one real spin → wager appears in `ReportById` / `GetWagerInfo`
- [ ] Idempotency tested (duplicate `txnCode` / `requestKey`)

### Platform side (per brand you enable)

- [ ] Game host + Resource deployed
- [ ] Game DB with tables + patterns for launched games
- [ ] Provider row points wallet to operator endpoint
- [ ] Lobby `VendorGames` / routing for agent

**Pragmatic (`slot-pragmatic`) ops:** see [PRAGMATIC_OPS.md](./PRAGMATIC_OPS.md) for add-game tooling, pattern fill, and completeness checks.

### Pragmatic Play notes for operators

| Topic | Behavior |
|-------|----------|
| Vendor | `slot-pragmatic` |
| Launch | `GetGameUrl` → `launchUrl` on `playGame.do` (do **not** call `gameService` yourself) |
| Buy bonus | Client sends buy; platform debits buy cost immediately, credits feature win once at the end |
| Promo FS | `ApplyFreeRound` then `GetGameUrl`. Bonus-buy titles only. Credit once at feature end |
| Close mid-FS | Unfinished round is stored. Reopen the same game to resume, or the stored win is paid if the round cannot continue |
| History | `GetDetailUrl` / `GetWagerInfo` / in-game history button |
| RTP | `ChangeUserRtp` / `lowRtp`+`highRtp` on `GetGameUrl` |

---

## 11. Example: seamless GetGameUrl

**Request**

```http
POST /api/casinoapi HTTP/1.1
Host: api.your-domain.com
Content-Type: application/json

{
  "method": "GetGameUrl",
  "token": "AGENT_TOKEN",
  "agentCode": "AGENT001",
  "userCode": "player1",
  "nickName": "Player One",
  "vendorCode": "slot-pragmatic",
  "gameCode": "vs20olympgate",
  "currencyCode": "USD",
  "language": "en",
  "homeUrl": "https://casino.example/lobby",
  "channel": "desktop"
}
```

**Response**

```json
{
  "status": 0,
  "msg": "OK",
  "errorId": 0,
  "launchUrl": "https://resource.pragmatic…/…?token=…&symbol=vs20olympgate…"
}
```

---

## 12. Quick method index

| method | Direction | Mode | Purpose |
|--------|-----------|------|---------|
| `CreateUser` | Op → Platform | both | Create player |
| `DeleteUser` | Op → Platform | both | Delete player |
| `ChangeUserPassword` | Op → Platform | both | Update nick/password vars |
| `GetUserInfo` | Op → Platform | both | Balances |
| `GetAgentInfo` | Op → Platform | both | Agent info |
| `Deposit` / `Withdraw` / `WithdrawAll` | Op → Platform | **transfer** | Move money |
| `GetVendors` | Op → Platform | both | Vendor list |
| `GetVendorGames` | Op → Platform | both | Game list |
| `GetGameUrl` | Op → Platform | both | **Launch** |
| `GetWagerInfo` | Op → Platform | both | One wager |
| `ReportById` / `ReportByDate` | Op → Platform | both | Wager reports |
| `GetDetailUrl` | Op → Platform | both | Round detail URL |
| `ApplyFreeRound` / `CancelFreeRound` | Op → Platform | both | Promo spins |
| `GetFreeRoundList` / `GetFreeRoundSupportMap` | Op → Platform | both | Promo inventory |
| `ChangeUserRtp` / `ChangeAgentRtp` | Op → Platform | both | RTP |
| `CallApply` / `CallCancel` / `GetCallList` / `GetCallHistory` | Op → Platform | both | Call system |
| `Get/SetGameSetting`, `Get/SetGameVariable(s)` | Op → Platform | both | Config |
| `GetCurrentPlayers` | Op → Platform | both | Live players |
| `EventPayment` | Op → Platform | both | Event payout |
| `GetBalance` | Platform → Op | **seamless** | Read balance |
| `ChangeBalance` | Platform → Op | **seamless** | Debit/credit/cancel |

---

*Generated from current InfinityPlay codebase. Confirm production base URLs and tokens with your deployment / backoffice.*

---

## 13. Backoffice (operator)

After login on the agent site:

| Menu | Use |
|------|-----|
| **API → API guide** | This document (HTML) plus PDF |
| **Game control → Launch & free rounds** | Open a game, Apply / Cancel promo FS |
| **Game control → Game list** | Per-agent game routing |
| **Agent → Agent treeview** | Create sub-agents, token, seamless wallet URL |
| **User → User list** | Players |
| **Report → By wager index** | Settled rounds |
| **Profile** | Password, API domain, wallet endpoint |

Hand operators: `https://{site-domain}/CommonAuthorize/ShowApiDoc` (or **API → API guide**).
