Every server request is scoped to the site bound to its API key. This guide describes the current integration flow. Detailed request/response schemas are available in the endpoint reference and `/sdk/openapi.json`.

## Addresses and environment
- Server API: `PROVIDER_ORIGIN`/provider/v1.
- Player client and `apiBase`: `PROVIDER_ORIGIN`/play/`SITE_SLUG`/.
- Main panel: `ADMIN_ORIGIN`/admin/.
- Site panel: `OPERATOR_ORIGIN`/operator/.
- Send API keys to the public provider API, never the panel domains. Panel authentication is separate.

Current game adapters use public demo sessions. Wallet mode is either seamless or transfer, configured per site. RESULT-AUTHORITY.en.txt explains the financial trust boundary of public demo results.

## Authentication and scopes
Server-to-server calls use Authorization: Bearer. JSON requests use Content-Type: application/json. Keep keys on your backend. Server-key API requests carrying a browser Origin header are rejected.

- launch: `/player`, `/launch` and player session revocation.
- read: `/catalog`, `/rooms`, `/results`, `/stats`, player balance and `/events`.
- wallet: transfer credits/debits and transfer receipts only.
- webhooks: `/webhooks/events`; `/events` still requires read.

Expiry and both key/site IP restrictions apply. The socket peer is the default source; an explicitly trusted proxy may supply verified `X-Real-IP`. See ACCESS-SECURITY.en.txt. These are API-key policy scopes, not OAuth scopes.

## Player identity
`POST /player`, with launch scope, resolves the account. The same tenant + `externalId` reuses the same member without creating another balance or alias. `externalId` is the authenticated site member key: 1–128 characters, letters/digits and - _ . : @.

```json Player request
{
  "externalId": "member-42",
  "name": "Atlas",
  "siteUsername": "atlas.site"
}
```

name is required only for a new member when no alias prefix exists. `siteUsername` preserves the original site login without changing `publicId`. `playerAliasPrefix`=cio assigns names such as cio1001 to new members; legacy names remain. Never let free-form browser input select another member.

`GET /player/{encodedExternalId}/balance` requires read and returns player plus `walletMode`. `availableBalance` is spendable; `lockedBalance` is reserved, both integer minor units. SDK: `client.player()`, `client.balance(externalId)`. Follow SEAMLESS-WALLET.en.txt to use the same site wallet.

## Game launch
`POST /launch` requires launch scope and returns HTTP 201 with `launchTicket`, url, `apiBase`, `expiresAt` and `parentOrigin`. The one-use ticket expires after 90 seconds. Request a fresh ticket on each launch; membership stays stable. A second launch revokes the previous player session.

```json Iframe launch request
{
  "externalId": "member-42",
  "name": "Atlas",
  "siteUsername": "atlas.site",
  "origin": "https://site.example",
  "route": "lobby",
  "mode": "iframe"
}
```

mode is iframe or module. origin is an exact allowlisted scheme + host + port, without path, query, wildcard or credentials. Use HTTPS; loopback development may use HTTP.

route: lobby, catalog, providers, history, rankings, competitions, room/ID, watch/ID, replay/ID or join/CODE. Room IDs are 10 lowercase hexadecimal characters; invite codes are 8 uppercase A–Z / 2–9 characters. Share your own site URL and issue a fresh launch for every visitor. Never share API keys or session tokens.

`POST /player/{externalId}/sessions/revoke` requires launch scope and an empty JSON body. It revokes game/read sessions and unused tickets. SDK: `client.revokeSessions(externalId)`.

## Catalog, rooms and reports
- `GET /catalog` → games, currency=TRY, environment=sandbox. SDK: `client.catalog()`.
- `GET /rooms?status=all` → rooms. status: all, waiting, running, completed, cancelled. SDK: `client.rooms()`; filter with `client.request('/rooms?status=waiting')`.
- `GET /results` → completed rooms. SDK: `client.results()`.
- `GET /stats?range=all` → statistics. range: all, today, week, month. Today uses the Istanbul day boundary; week means 7 days and month means 30 days. SDK: `client.statistics({range:'month'})`.

The catalog includes only platform/site-enabled games and bonus choices. `buyAmounts` are exact integer minor-unit quotes; `bonusChoices` contains standard/super metadata. Ante/boosters are not bonus-buy choices. Multi-game rooms require a common supported amount across every chosen variant. Changed prices or policy never silently substitute another bonus.

Report fields include `entryVolume`, refunds, `totalWinnings`, `paidPrizes`, `pendingPrizes`, commission, `providerRevenue`, `operatorShare`, `transferCredits`, `transferDebits`, income, expenses and `netProfit`. Entry volume and wallet transfers are not profit. Room lists are bounded history views; use cursor events and reports for reconciliation.

## Transfer wallet — separate mode
For one spendable site/game balance, use seamless. `/wallet/transfer` applies only to transfer-mode sites and is rejected for seamless sites. Amounts are integer TRY minor units: 20000 = TRY 200.00. `amountMinor` must be 1–1,000,000,000.

```json Transfer request
{
  "externalId": "member-42",
  "direction": "credit",
  "amountMinor": 20000,
  "reference": "credit-order-00042"
}
```

`POST /wallet/transfer` requires wallet scope. direction is credit or debit. reference is 8–100 characters, letters/digits and - _ . :. If supplied, Idempotency-Key must exactly match reference. The same reference and content returns the original receipt without another financial effect. Conflicting content returns HTTP 409.

After a timeout, never create a new reference. Read `GET /wallet/transfers/{reference}` or retry the original request. Debit cannot spend room holds. SDK: `client.credit()`, `client.debit()`, `client.transferReceipt(reference)`. IDENTITY-WALLET.en.txt documents durable transfer handling; SEAMLESS-WALLET.en.txt separately defines reserve/refund/settle callbacks.

## Event stream and retries
`GET /events?cursor=0&limit=100` requires read. `GET /webhooks/events` exposes the same ledger through webhooks scope. Both are pull APIs, not payment callbacks. Signed seamless-wallet callbacks are a separate protocol.

cursor is a nonnegative integer; limit is 1–200. Responses include events and `nextCursor`. Deduplicate event.id/cursor and persist the events with the new cursor in one database transaction. Empty responses keep the cursor unchanged. Resume from the original cursor after failure. SDK: `client.events(cursor)`, `client.webhookEvents(cursor)`.

## Shared rooms and settlement
New rooms use the shared pool while each player retains their source site identity and wallet. Each client keeps its own `/play/SITE_SLUG/` `apiBase` and launch/read session. Another site's `externalId`, balance, receipt or token is never exposed to players. Invite restrictions still apply.

Read `capabilities.maxGamePool` for the pool size limit (default 20). The chosen bonus and price are frozen once for all seats. Site/game/bonus/amount policy is validated on joining and starting. Reloading does not reroll the selection.

`feeBps` is snapshotted when creating the room; each seat's `providerShareBps` is frozen on entry. 500 bps = 5%. The fee is `floor(totalWinnings × feeBps / 10000)`; the highest score receives the net pool. Ties split it, allocating leftover minor units in seat order. Commission is allocated across source sites by their players' gross winnings, then split using each seat's provider/operator ratio. Sum of prizes + fees equals gross winnings.

completed means the battle finished. Show a credited prize only when `settlementStatus`=complete. pending means source-wallet reconciliation is still running. An uncertain turn must not generate another purchase or an estimated result. ROOM-REVIEWS.en.txt describes player reports and authorized review.

## Errors and operations
Errors return JSON error and code. SDK errors expose status/code. A network timeout is not a definitive rejection.

- 400: invalid field, value or reference format.
- 401: invalid or expired authentication.
- 403: scope, source IP or origin denied.
- 404: resource or receipt not found.
- 409: conflict, insufficient funds or invalid state.
- 415: JSON body required.
- 429: rate limit; back off while preserving the original operation identity.
- 503: maintenance or new admissions paused.

Redact keys, signing secrets and launch/player/read tokens from logs. Use HTTPS/WSS, exact origins, suitable CSP and verified proxy settings. Keep outbox entries and receipts durable; reconcile with the operator ledger after restoring backups. Local browser tests do not establish physical-mobile, WAN or high-concurrency acceptance.

## Related guides
README.en.txt covers setup examples; WALLET-CONFIG.en.txt configures callbacks; ACCESS-SECURITY.en.txt covers key/IP/2FA boundaries; OPERATOR-API.en.txt covers staff and support; CHAT-MODERATION.en.txt covers chat permissions. Panel APIs use their own cookie/CSRF sessions, not the operator server key.

## Period battles — site reporting

Track daily, weekly and monthly entries in Operator / Period battles. Only your site's participants, private member identities, amounts and prizes are visible; ranks are computed across all sites. Staff require `rooms.read`, `players.read` and `finance.read`. From your backend use `GET /provider/v1/competitions?kind=daily&limit=50&offset=0` (`read` scope) or `client.competitions({kind: 'daily'})`. Currency is TRY and amounts are minor units. Paid and pending awards are separate. Follow pagination, event-context and package-update guidance in [PERIOD-WARS.en.txt](PERIOD-WARS.en.txt). Existing iframe integration remains valid; modules require the updated client ZIP.
