{
  "openapi": "3.1.0",
  "info": {
    "title": "Arena Battle Operator Integration",
    "version": "15.55.1",
    "description": "Server-to-server identity and wallet contract. Amounts are integer TRY minor units. The API key chooses exactly one tenant; never place keys in HTML, browser JS, iframe URLs or public module packages. Requests carrying a browser Origin header are rejected. Scopes are key-policy scopes documented per operation with x-required-api-scope (not OAuth scopes). Main-admin playerAliasPrefix config enables sequential public aliases; see TenantIdentityConfiguration. Existing legacy names remain unchanged. Wallet mode is configured per tenant. In seamless mode the operator wallet is authoritative: signed balance/reserve/refund/settle callbacks keep one spendable balance; /wallet/transfer is disabled. Transfer mode remains available for existing integrations. Callback receiver and integration guide: /sdk/slot-battles-seamless-wallet.mjs and /sdk/SEAMLESS-WALLET.txt. Optional siteUsername is trusted operator-account metadata, visible only in server/admin responses; it never changes the immutable public alias.\nR26: Server APIs require the API key scopes and both the key-level and enabled tenant-level source IP policies. The socket peer is the default source IP. Explicit TRUSTED_PROXY_IPS may provide one verified X-Real-IP value; untrusted forwarding headers are ignored. The trusted proxy must overwrite this header and keep the backend private. See ACCESS-SECURITY.txt / ACCESS-SECURITY.en.txt.\nR27: Staff-confirmed room fault refunds use the existing signed refund callback, preserving original transaction identities. Panel review/team routes use separate cookie/CSRF sessions, not OperatorApiKey; see ROOM-REVIEWS.txt / ROOM-REVIEWS.en.txt.\nR28: Tenant-scoped room/spectator chat and SVG reactions are moderated server-side. Panel chat APIs use separate cookie/CSRF sessions and chat.read/chat.manage, never OperatorApiKey. Restrictions affect chat only. See CHAT-MODERATION.txt / CHAT-MODERATION.en.txt."
  },
  "servers": [
    {
      "url": "https://provider.example",
      "description": "Replace with your configured provider origin. Local loopback development uses its configured HTTP origin."
    }
  ],
  "security": [
    {
      "OperatorApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Provider server API",
      "description": "Operator-backend-only endpoints; never call directly from a customer browser."
    },
    {
      "name": "Chat panel API",
      "description": "Provider/operator staff cookie sessions; separate from server integration keys."
    },
    {
      "name": "Player social API",
      "description": "Existing launch-issued player session; canonical public aliases and source-site moderation."
    },
    {
      "name": "Billing panel API",
      "description": "Staff cookie sessions only. Service invoices do not move player funds."
    }
  ],
  "paths": {
    "/provider/v1/player": {
      "post": {
        "operationId": "ensurePlayer",
        "tags": [
          "Provider server API"
        ],
        "summary": "Create or retrieve one durable tenant-scoped operator player",
        "description": "Create or retrieve one durable tenant-scoped operator player. Repeated externalId returns the same id/publicId/name and never credits funds or renames a player. The configured prefix determines whether name is needed for a new account.",
        "x-required-api-scope": "launch",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlayerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlayerRequest"
              }
            }
          }
        }
      }
    },
    "/provider/v1/launch": {
      "post": {
        "operationId": "launchPlayer",
        "tags": [
          "Provider server API"
        ],
        "summary": "Issue a short-lived single-use launch ticket for iframe or file/module integration",
        "description": "Issue a short-lived single-use launch ticket for iframe or file/module integration. The operator backend resolves externalId from its authenticated session; browser-supplied free-form identities must never select accounts. Each site/externalId remains stable across relaunches.",
        "x-required-api-scope": "launch",
        "responses": {
          "201": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LaunchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LaunchRequest"
              }
            }
          }
        }
      }
    },
    "/provider/v1/player/{externalId}/balance": {
      "get": {
        "operationId": "playerBalance",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read the authoritative gaming wallet, stable public code and separate available/locked funds for this operator player",
        "description": "Read the authoritative gaming wallet, stable public code and separate available/locked funds for this operator player. The site wallet and gaming wallet are separate transfer-wallet partitions, not two spendable copies of one balance. In seamless mode this refreshes from the authoritative operator wallet. Callback unavailability returns503 rather than a false fresh balance.",
        "x-required-api-scope": "read",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlayerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ExternalId"
            }
          }
        ]
      }
    },
    "/provider/v1/wallet/transfer": {
      "post": {
        "operationId": "transferWallet",
        "tags": [
          "Provider server API"
        ],
        "summary": "Apply an immutable idempotent transfer",
        "description": "Apply an immutable idempotent transfer. Same reference+externalId+direction+amount returns the original receipt without another money effect; current player balance may have changed. A conflicting reference returns 409. Debit cannot spend locked funds. Reuse the exact reference after timeouts; validate the receipt before crediting the site wallet. Transfer mode only: seamless tenants return409; their wallet is changed through signed operator callbacks.",
        "x-required-api-scope": "wallet",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TransferReference"
            },
            "description": "If present, must exactly equal body.reference."
          }
        ]
      }
    },
    "/provider/v1/wallet/transfers/{reference}": {
      "get": {
        "operationId": "getTransferReceipt",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read an original committed transfer receipt and the current player wallet",
        "description": "Read an original committed transfer receipt and the current player wallet. Requires wallet scope, not read. A 404 is only a point-in-time lookup result, not proof that an in-flight transfer cannot later commit. Resolve unknown results using the same immutable request reference.",
        "x-required-api-scope": "wallet",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/TransferReference"
            }
          }
        ]
      }
    },
    "/provider/v1/player/{externalId}/sessions/revoke": {
      "post": {
        "operationId": "revokePlayerSessions",
        "tags": [
          "Provider server API"
        ],
        "summary": "Revoke all current player/read tokens and outstanding unconsumed launch tickets for this operator account; disconnect its active local/shared streams",
        "description": "Revoke all current player/read tokens and outstanding unconsumed launch tickets for this operator account; disconnect its active local/shared streams. Repeating for a known account returns zero counts. Unknown player returns 404. Wallets and ongoing rooms are not cancelled. Coordinate logout with in-flight launch requests on the operator backend.",
        "x-required-api-scope": "launch",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevokeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ExternalId"
            }
          }
        ]
      }
    },
    "/provider/v1/events": {
      "get": {
        "operationId": "readLedgerEvents",
        "tags": [
          "Provider server API"
        ],
        "summary": "Pull ordered tenant ledger events by cursor",
        "description": "Pull ordered tenant ledger events by cursor. Persist event IDs and nextCursor together transactionally; retry unchanged cursor on failure. Events are audit/refresh signals, never an instruction to credit a second copy of the wallet.",
        "x-required-api-scope": "read",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ]
      }
    },
    "/provider/v1/webhooks/events": {
      "get": {
        "operationId": "readWebhookLedgerEvents",
        "tags": [
          "Provider server API"
        ],
        "summary": "Pull the same ordered tenant ledger cursor using a dedicated webhooks-scope key",
        "description": "Pull the same ordered tenant ledger cursor using a dedicated webhooks-scope key. This is polling, not an outbound seamless-wallet or webhook-delivery service.",
        "x-required-api-scope": "webhooks",
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "409": {
            "$ref": "#/components/responses/Error409"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ]
      }
    },
    "/play/{slug}/api/telemetry": {
      "post": {
        "summary": "Record bounded session risk context",
        "description": "Authenticated browser-only player endpoint; Origin must match the issued session and configured site. Raw socket peer IP is authoritative; X-Forwarded-For/Forwarded/X-Real-IP are ignored. User-agent/client hints and context are untrusted signals. No precise geolocation or fingerprinting. Device context retained for 90 days. Returns no device hash or other player metadata. 30 requests/minute/player.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9-]{2,31}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlayerDeviceContext"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Context recorded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid or unsupported context fields"
          },
          "401": {
            "description": "Player session required"
          },
          "403": {
            "description": "Origin rejected"
          },
          "429": {
            "description": "Per-player request limit"
          }
        },
        "operationId": "recordPlayerDeviceContext"
      }
    },
    "/play/{slug}/api/session-status": {
      "get": {
        "tags": [
          "Player session"
        ],
        "summary": "Validate the current player session without changing it",
        "description": "A new redeemed launch for the same tenant/externalId replaces its prior session. This read does not rotate the session, seat or wallet. Supplied replaced/invalid credentials cannot fall back to guest access.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current authenticated session",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Expired, invalid or replaced player session. PLAYER_SESSION_REPLACED ends local playback/reconnect and requires an explicit new operator launch."
          }
        },
        "operationId": "validatePlayerSession"
      }
    },
    "/control/api/chat": {
      "get": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "providerChatFeed",
        "summary": "Read scoped chat messages, restrictions and events",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "x-required-panel-permission": "chat.read",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "all or tenant ID; operator remains own-site only."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatModerationFeed"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/control/api/chat/settings": {
      "post": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "providerChatSettings",
        "summary": "Update source-site chat setting",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token. Only chat is changed; games, seats, wallets and refunds are unaffected.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "chat.manage",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatSettingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "setting": {
                      "$ref": "#/components/schemas/ChatSetting"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/control/api/chat/moderate": {
      "post": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "providerChatModerate",
        "summary": "Ban, time out or unban a site player in chat",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token. Only chat is changed; games, seats, wallets and refunds are unaffected.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "chat.manage",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatModerateInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "restriction": {
                      "$ref": "#/components/schemas/ChatRestriction"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/operator-api/chat": {
      "get": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "operatorChatFeed",
        "summary": "Read scoped chat messages, restrictions and events",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "x-required-panel-permission": "chat.read",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "all or tenant ID; operator remains own-site only."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatModerationFeed"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/operator-api/chat/settings": {
      "post": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "operatorChatSettings",
        "summary": "Update source-site chat setting",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token. Only chat is changed; games, seats, wallets and refunds are unaffected.",
        "security": [
          {
            "OperatorPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "chat.manage",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatSettingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "setting": {
                      "$ref": "#/components/schemas/ChatSetting"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/operator-api/chat/moderate": {
      "post": {
        "tags": [
          "Chat panel API"
        ],
        "operationId": "operatorChatModerate",
        "summary": "Ban, time out or unban a site player in chat",
        "description": "Provider can select all or one tenant. Operator is always scoped to its session tenant; another tenant is rejected. Never use an operator server API key or player token. Only chat is changed; games, seats, wallets and refunds are unaffected.",
        "security": [
          {
            "OperatorPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "chat.manage",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatModerateInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "restriction": {
                      "$ref": "#/components/schemas/ChatRestriction"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/play/{slug}/api/social": {
      "get": {
        "tags": [
          "Player social API"
        ],
        "operationId": "playerSocialFeed",
        "summary": "Read room/spectator chat and own moderation state",
        "description": "Existing room visibility and channel access rules apply. Disabled sites receive empty message/reaction feeds. Canonical aliases are returned.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "room",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "enum": [
                "room",
                "tribune"
              ],
              "default": "tribune"
            }
          },
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlayerSocialFeed"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/play/{slug}/api/chat": {
      "post": {
        "tags": [
          "Player social API"
        ],
        "operationId": "playerChat",
        "summary": "Post a chat message",
        "description": "Uses the existing player session. Moderation is enforced by source site for room/spectator/shared-room use. Retries use the same key. Rejected content is never published and must not be auto-retried with new keys.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "$ref": "#/components/schemas/ChatOperationKey"
                  },
                  "roomId": {
                    "type": "string"
                  },
                  "channel": {
                    "enum": [
                      "room",
                      "tribune"
                    ],
                    "default": "tribune"
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300
                  }
                },
                "required": [
                  "key",
                  "roomId",
                  "message"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMessage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/play/{slug}/api/reactions": {
      "post": {
        "tags": [
          "Player social API"
        ],
        "operationId": "playerReactions",
        "summary": "Post a themed reaction",
        "description": "Uses the existing player session. Moderation is enforced by source site for room/spectator/shared-room use. Retries use the same key. Rejected content is never published and must not be auto-retried with new keys.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider origin for panel writes; allowed integration origin for player writes."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "$ref": "#/components/schemas/ChatOperationKey"
                  },
                  "roomId": {
                    "type": "string"
                  },
                  "emoji": {
                    "type": "string",
                    "enum": [
                      "🔥",
                      "👏",
                      "💎",
                      "😮",
                      "😂",
                      "🎉"
                    ],
                    "description": "Compatibility wire value; current client renders original SVG artwork."
                  }
                },
                "required": [
                  "key",
                  "roomId",
                  "emoji"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields, action, reason or operation key."
          },
          "401": {
            "description": "Valid matching session required."
          },
          "403": {
            "description": "Not permitted, wrong site, CSRF/origin mismatch, disabled or banned."
          },
          "404": {
            "description": "Site/player/room not found or not visible."
          },
          "409": {
            "description": "Operation key conflict."
          },
          "422": {
            "description": "Message rejected with filter warning."
          },
          "429": {
            "description": "Timeout or rate limit."
          }
        }
      }
    },
    "/provider/v1/catalog": {
      "get": {
        "operationId": "readCatalog",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read the site-enabled game and bonus-buy catalog",
        "x-required-api-scope": "read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/provider/v1/rooms": {
      "get": {
        "operationId": "readRooms",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read visible rooms for the current site",
        "x-required-api-scope": "read",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "waiting",
                "running",
                "completed",
                "cancelled"
              ],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoomsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/provider/v1/results": {
      "get": {
        "operationId": "readRoomsResults",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read completed rooms for the current site",
        "x-required-api-scope": "read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoomsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/provider/v1/stats": {
      "get": {
        "operationId": "readStatistics",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read the site finance and operations report",
        "x-required-api-scope": "read",
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "today",
                "week",
                "month"
              ],
              "default": "all"
            },
            "description": "Istanbul day boundary; week means 7 days and month means 30 days."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatisticsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        }
      }
    },
    "/provider/v1/competitions": {
      "get": {
        "operationId": "readSitePeriodBattles",
        "tags": [
          "Provider server API"
        ],
        "summary": "Read own-site period participants, global ranks and acknowledged prizes",
        "description": "Tenant is resolved exclusively from the authenticated key/session. No tenant selector is accepted. Unknown and duplicate query fields are rejected. This is read-only and cannot reserve, refund or award funds.",
        "security": [
          {
            "OperatorApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "daily",
                "weekly",
                "monthly"
              ],
              "default": "daily"
            }
          },
          {
            "name": "periodId",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
            },
            "description": "Exact archived period ID matching kind. Omit for the latest period. History lists the latest 100 periods; older known IDs remain readable."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000000,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Site-scoped report; monetary values are integer TRY minor units.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SitePeriodReport"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          },
          "404": {
            "description": "Requested period does not exist or does not match kind."
          }
        },
        "x-required-api-scope": "read"
      }
    },
    "/operator-api/competitions": {
      "get": {
        "operationId": "operatorPeriodBattles",
        "tags": [
          "Operator period reports"
        ],
        "summary": "Read own-site period participants, global ranks and acknowledged prizes",
        "description": "Tenant is resolved exclusively from the authenticated key/session. No tenant selector is accepted. Unknown and duplicate query fields are rejected. This is read-only and cannot reserve, refund or award funds.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "daily",
                "weekly",
                "monthly"
              ],
              "default": "daily"
            }
          },
          {
            "name": "periodId",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
            },
            "description": "Exact archived period ID matching kind. Omit for the latest period. History lists the latest 100 periods; older known IDs remain readable."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000000,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Site-scoped report; monetary values are integer TRY minor units.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SitePeriodReport"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          },
          "404": {
            "description": "Requested period does not exist or does not match kind."
          }
        },
        "x-required-panel-permissions": [
          "rooms.read",
          "players.read",
          "finance.read"
        ]
      }
    },
    "/control/api/billing": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /control/api/billing",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Site ID or all (default)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000,
              "default": 1
            },
            "description": "50 rows per page; summary totals cover all matching invoices."
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      }
    },
    "/control/api/billing/settings": {
      "patch": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "PATCH /control/api/billing/settings",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingGlobalSettings"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/sites/{tenantId}": {
      "patch": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "PATCH /control/api/billing/sites/{tenantId}",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "tenantId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingSiteSettings"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices": {
      "post": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "POST /control/api/billing/invoices",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [],
        "responses": {
          "201": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingDraft"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /control/api/billing/invoices/{invoiceId}",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      },
      "patch": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "PATCH /control/api/billing/invoices/{invoiceId}",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingEdit"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}/pdf": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /control/api/billing/invoices/{invoiceId}/pdf",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "tr",
                "en"
              ]
            },
            "description": "Current panel language. Defaults to the invoice language if omitted. Does not modify the invoice or email recipient language."
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      }
    },
    "/operator-api/billing": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /operator-api/billing",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000,
              "default": 1
            },
            "description": "50 rows per page; summary totals cover all matching invoices."
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      }
    },
    "/operator-api/billing/invoices/{invoiceId}": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /operator-api/billing/invoices/{invoiceId}",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      }
    },
    "/operator-api/billing/invoices/{invoiceId}/pdf": {
      "get": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "GET /operator-api/billing/invoices/{invoiceId}/pdf",
        "description": "Requires finance.read. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "x-required-panel-permission": "finance.read",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "tr",
                "en"
              ]
            },
            "description": "Current panel language. Defaults to the invoice language if omitted. Does not modify the invoice or email recipient language."
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}/issue": {
      "post": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "POST /control/api/billing/invoices/{invoiceId}/issue",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}/payments": {
      "post": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "POST /control/api/billing/invoices/{invoiceId}/payments",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingPayment"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}/void": {
      "post": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "POST /control/api/billing/invoices/{invoiceId}/void",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingVoid"
              }
            }
          }
        }
      }
    },
    "/control/api/billing/invoices/{invoiceId}/email": {
      "post": {
        "tags": [
          "Billing panel API"
        ],
        "summary": "POST /control/api/billing/invoices/{invoiceId}/email",
        "description": "Requires finance.manage. Writes also require the matching panel Origin. Read BILLING.txt / BILLING.en.txt for lifecycle, snapshots, email switches and accounting scope.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "finance.manage",
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated invoice or billing result. Operator responses are restricted to the session site.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields or amount"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission or CSRF validation failed"
          },
          "404": {
            "description": "Not found in this site"
          },
          "409": {
            "description": "Lifecycle, duplicate reference, pending review or configuration conflict"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillingEmail"
              }
            }
          }
        }
      }
    },
    "/control/api/risk/sites/{tenantId}/rules": {
      "get": {
        "tags": [
          "Risk"
        ],
        "summary": "GET /control/api/risk/sites/{tenantId}/rules",
        "description": "Review thresholds only. Operator site comes from the authenticated session. PATCH accepts rules or reset=true, never both. Automatic cancellation is not a site-editable rule.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "x-required-panel-permission": "risk.read",
        "parameters": [
          {
            "name": "tenantId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current thresholds, defaults and customization state"
          },
          "400": {
            "description": "Invalid threshold or fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission, origin or CSRF check failed"
          }
        }
      },
      "patch": {
        "tags": [
          "Risk"
        ],
        "summary": "PATCH /control/api/risk/sites/{tenantId}/rules",
        "description": "Review thresholds only. Operator site comes from the authenticated session. PATCH accepts rules or reset=true, never both. Automatic cancellation is not a site-editable rule.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "risk.manage",
        "parameters": [
          {
            "name": "tenantId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current thresholds, defaults and customization state"
          },
          "400": {
            "description": "Invalid threshold or fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission, origin or CSRF check failed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteRiskUpdate"
              }
            }
          }
        }
      }
    },
    "/operator-api/risk/rules": {
      "get": {
        "tags": [
          "Risk"
        ],
        "summary": "GET /operator-api/risk/rules",
        "description": "Review thresholds only. Operator site comes from the authenticated session. PATCH accepts rules or reset=true, never both. Automatic cancellation is not a site-editable rule.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "x-required-panel-permission": "risk.read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current thresholds, defaults and customization state"
          },
          "400": {
            "description": "Invalid threshold or fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission, origin or CSRF check failed"
          }
        }
      },
      "patch": {
        "tags": [
          "Risk"
        ],
        "summary": "PATCH /operator-api/risk/rules",
        "description": "Review thresholds only. Operator site comes from the authenticated session. PATCH accepts rules or reset=true, never both. Automatic cancellation is not a site-editable rule.",
        "security": [
          {
            "OperatorPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "x-required-panel-permission": "risk.manage",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current thresholds, defaults and customization state"
          },
          "400": {
            "description": "Invalid threshold or fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Permission, origin or CSRF check failed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteRiskUpdate"
              }
            }
          }
        }
      }
    },
    "/control/api/preferences": {
      "get": {
        "tags": [
          "Panel preferences"
        ],
        "summary": "GET /control/api/preferences",
        "description": "Own authenticated staff account only. PATCH requires the panel Origin and CSRF token. Language survives logout and is returned in login/session responses as preferences.locale. GET locale is null until saved.",
        "security": [
          {
            "ProviderPanelSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Own language preference"
          },
          "400": {
            "description": "Invalid locale or unknown fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Origin or CSRF validation failed"
          }
        }
      },
      "patch": {
        "tags": [
          "Panel preferences"
        ],
        "summary": "PATCH /control/api/preferences",
        "description": "Own authenticated staff account only. PATCH requires the panel Origin and CSRF token. Language survives logout and is returned in login/session responses as preferences.locale. GET locale is null until saved.",
        "security": [
          {
            "ProviderPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "responses": {
          "200": {
            "description": "Own language preference"
          },
          "400": {
            "description": "Invalid locale or unknown fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Origin or CSRF validation failed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PanelLanguagePreference"
              }
            }
          }
        }
      }
    },
    "/operator-api/preferences": {
      "get": {
        "tags": [
          "Panel preferences"
        ],
        "summary": "GET /operator-api/preferences",
        "description": "Own authenticated staff account only. PATCH requires the panel Origin and CSRF token. Language survives logout and is returned in login/session responses as preferences.locale. GET locale is null until saved.",
        "security": [
          {
            "OperatorPanelSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Own language preference"
          },
          "400": {
            "description": "Invalid locale or unknown fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Origin or CSRF validation failed"
          }
        }
      },
      "patch": {
        "tags": [
          "Panel preferences"
        ],
        "summary": "PATCH /operator-api/preferences",
        "description": "Own authenticated staff account only. PATCH requires the panel Origin and CSRF token. Language survives logout and is returned in login/session responses as preferences.locale. GET locale is null until saved.",
        "security": [
          {
            "OperatorPanelSession": [],
            "PanelCsrf": []
          }
        ],
        "responses": {
          "200": {
            "description": "Own language preference"
          },
          "400": {
            "description": "Invalid locale or unknown fields"
          },
          "401": {
            "description": "Panel sign-in required"
          },
          "403": {
            "description": "Origin or CSRF validation failed"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PanelLanguagePreference"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "OperatorApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Tenant-bound operator API key. Required scope: launch, read, wallet or webhooks as stated per operation. Keep server-side; key policy may enforce IP allowlist and expiry."
      },
      "WalletSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Slot-Wallet-Signature",
        "description": "Hex HMAC-SHA256(sharedSecret,timestamp+\".\"+rawJSON). Request and response MUST be signed; secret stays on server."
      },
      "WalletTimestamp": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Slot-Wallet-Timestamp",
        "description": "Unix milliseconds, within60seconds. Include exact header text in HMAC input."
      },
      "BrowserSession": {
        "type": "http",
        "scheme": "bearer",
        "description": "Short-lived player session issued by the browser launch exchange. Never use the operator API key here."
      },
      "ProviderPanelSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ss_admin",
        "description": "Provider staff panel session issued by the existing login/2FA flow."
      },
      "OperatorPanelSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ss_operator",
        "description": "Site staff panel session issued by the existing login/2FA flow; always scoped to its own tenant."
      },
      "PanelCsrf": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CSRF-Token",
        "description": "CSRF token from the current matching panel session. Writes also require the provider Origin."
      }
    },
    "schemas": {
      "ExternalId": {
        "type": "string",
        "pattern": "^[-A-Za-z0-9_.:@]{1,128}$",
        "description": "Immutable operator account ID, resolved only from the authenticated operator server session. Tenant is selected by the API key, not by this ID."
      },
      "TransferReference": {
        "type": "string",
        "pattern": "^[-A-Za-z0-9_:.]{8,100}$",
        "description": "Durable, tenant-unique transfer reference. Reuse the same reference and unchanged payload after an unknown result."
      },
      "MinorBalance": {
        "type": "integer",
        "format": "int64",
        "minimum": 0,
        "maximum": 1000000000000,
        "description": "Integer kuruş (TRY minor units); 20000 means 200.00 TRY."
      },
      "EpochMilliseconds": {
        "type": "integer",
        "format": "int64",
        "minimum": 0,
        "description": "Unix epoch milliseconds."
      },
      "PublicId": {
        "type": "string",
        "pattern": "^[a-z]{1,12}[0-9]{4,12}$",
        "description": "Immutable tenant-scoped public player code, e.g. cio1001. Sequence starts at 1001. Compare tenant + publicId, not publicId alone across sites."
      },
      "PublicPlayer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "publicId": {
            "$ref": "#/components/schemas/PublicId"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "publicId",
          "name"
        ],
        "additionalProperties": false
      },
      "Player": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "publicId": {
            "$ref": "#/components/schemas/PublicId"
          },
          "name": {
            "type": "string"
          },
          "balance": {
            "$ref": "#/components/schemas/MinorBalance"
          },
          "availableBalance": {
            "$ref": "#/components/schemas/MinorBalance"
          },
          "lockedBalance": {
            "$ref": "#/components/schemas/MinorBalance",
            "description": "Local waiting/running buy-ins plus unresolved source-site shared-room holds. Already excluded from availableBalance; never subtract twice."
          },
          "bot": {
            "type": "boolean"
          },
          "colorIndex": {
            "type": "integer",
            "minimum": 0,
            "maximum": 11
          },
          "siteUsername": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\u0000-\\u001f\\u007f]+$",
            "description": "Original operator-site username/account label from the authenticated backend session. Optional; explicit values update this private metadata only. Never selects an account or changes publicId/name. externalId remains the immutable site account key. When first registering, legacy name is used as a fallback; later omitted siteUsername preserves the saved value."
          },
          "siteIdentityUpdatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Private metadata update time in epoch milliseconds; null until captured."
          }
        },
        "required": [
          "id",
          "externalId",
          "publicId",
          "name",
          "balance",
          "availableBalance",
          "lockedBalance"
        ],
        "additionalProperties": false
      },
      "PlayerRequest": {
        "type": "object",
        "properties": {
          "externalId": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 24,
            "description": "Legacy display name. Required only when creating a previously unknown player on a site whose playerAliasPrefix is empty. Ignored for an existing account and when generated aliases are enabled."
          },
          "siteUsername": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\u0000-\\u001f\\u007f]+$",
            "description": "Original operator-site username/account label from the authenticated backend session. Optional; explicit values update this private metadata only. Never selects an account or changes publicId/name. externalId remains the immutable site account key. When first registering, legacy name is used as a fallback; later omitted siteUsername preserves the saved value."
          }
        },
        "required": [
          "externalId"
        ],
        "additionalProperties": false
      },
      "PlayerResponse": {
        "type": "object",
        "properties": {
          "player": {
            "$ref": "#/components/schemas/Player"
          }
        },
        "required": [
          "player"
        ],
        "additionalProperties": false
      },
      "LaunchRequest": {
        "type": "object",
        "properties": {
          "externalId": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 24,
            "description": "Legacy display name. Required only when creating a previously unknown player on a site whose playerAliasPrefix is empty. Ignored for an existing account and when generated aliases are enabled."
          },
          "origin": {
            "type": "string",
            "format": "uri",
            "description": "Exact allowlisted operator origin (scheme, host, optional port), no path/query/fragment/trailing slash. HTTPS except loopback development origins."
          },
          "route": {
            "type": "string",
            "default": "lobby",
            "pattern": "^(lobby|catalog|providers|history|rankings|competitions|create|join/[A-Z2-9]{8}|(?:room|watch|replay)/[a-f0-9]{10})$"
          },
          "mode": {
            "type": "string",
            "enum": [
              "iframe",
              "module"
            ],
            "default": "iframe"
          },
          "siteUsername": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\u0000-\\u001f\\u007f]+$",
            "description": "Original operator-site username/account label from the authenticated backend session. Optional; explicit values update this private metadata only. Never selects an account or changes publicId/name. externalId remains the immutable site account key. When first registering, legacy name is used as a fallback; later omitted siteUsername preserves the saved value."
          }
        },
        "required": [
          "externalId",
          "origin"
        ],
        "additionalProperties": false
      },
      "LaunchResponse": {
        "type": "object",
        "properties": {
          "player": {
            "$ref": "#/components/schemas/PublicPlayer"
          },
          "launchTicket": {
            "type": "string",
            "description": "Single-use 90-second ticket. Keep out of logs/analytics. Exchange in browser through the provider client; never expose the operator API key."
          },
          "expiresAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "apiBase": {
            "type": "string",
            "format": "uri"
          },
          "parentOrigin": {
            "type": "string",
            "format": "uri"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "tenant": {
            "$ref": "#/components/schemas/TenantBranding"
          }
        },
        "required": [
          "player",
          "launchTicket",
          "expiresAt",
          "apiBase",
          "parentOrigin",
          "url"
        ],
        "additionalProperties": false
      },
      "TransferRequest": {
        "type": "object",
        "properties": {
          "externalId": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "direction": {
            "type": "string",
            "enum": [
              "credit",
              "debit"
            ],
            "description": "credit moves funds into the gaming wallet; debit moves available funds out. These are not game prizes or betting ledger entries."
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000000
          },
          "reference": {
            "$ref": "#/components/schemas/TransferReference"
          }
        },
        "required": [
          "externalId",
          "direction",
          "amountMinor",
          "reference"
        ],
        "additionalProperties": false
      },
      "Transfer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId"
          },
          "reference": {
            "$ref": "#/components/schemas/TransferReference"
          },
          "direction": {
            "type": "string",
            "enum": [
              "credit",
              "debit"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000000
          },
          "balanceAfter": {
            "$ref": "#/components/schemas/MinorBalance",
            "description": "Original committed transfer balance, immutable on replay. Use player.availableBalance for the current balance."
          },
          "createdAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          }
        },
        "required": [
          "id",
          "externalId",
          "reference",
          "direction",
          "amountMinor",
          "balanceAfter",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "TransferResponse": {
        "type": "object",
        "properties": {
          "transfer": {
            "$ref": "#/components/schemas/Transfer"
          },
          "player": {
            "$ref": "#/components/schemas/Player"
          }
        },
        "required": [
          "transfer",
          "player"
        ],
        "additionalProperties": false
      },
      "RevokeRequest": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "RevokeResponse": {
        "type": "object",
        "properties": {
          "player": {
            "$ref": "#/components/schemas/PublicPlayer"
          },
          "revoked": {
            "type": "object",
            "properties": {
              "sessions": {
                "type": "integer",
                "minimum": 0
              },
              "readSessions": {
                "type": "integer",
                "minimum": 0
              },
              "launchTickets": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "sessions",
              "readSessions",
              "launchTickets"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "player",
          "revoked"
        ],
        "additionalProperties": false
      },
      "LedgerEvent": {
        "type": "object",
        "properties": {
          "cursor": {
            "type": "integer",
            "minimum": 1
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "externalId": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ExternalId"
              },
              {
                "type": "null"
              }
            ]
          },
          "roomId": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "description": "Ledger type, such as transfer-credit, transfer-debit, reserve, refund, prize, shared-reserve, shared-refund or shared-prize. Future event kinds may be added."
          },
          "amountMinor": {
            "type": "integer",
            "minimum": -1000000000000,
            "maximum": 1000000000000
          },
          "balanceAfter": {
            "$ref": "#/components/schemas/MinorBalance"
          },
          "at": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "competition": {
            "$ref": "#/components/schemas/PeriodLedgerContext"
          }
        },
        "required": [
          "cursor",
          "id",
          "externalId",
          "roomId",
          "kind",
          "amountMinor",
          "balanceAfter",
          "at"
        ],
        "additionalProperties": false
      },
      "EventsResponse": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/LedgerEvent"
            }
          },
          "nextCursor": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "events",
          "nextCursor"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": true
      },
      "TenantIdentityConfiguration": {
        "type": "object",
        "properties": {
          "playerAliasPrefix": {
            "type": "string",
            "pattern": "^(|[a-z]{2,12})$",
            "default": "",
            "description": "Configure in main admin site settings. Empty preserves legacy display-name enrollment; nonempty generates NEW accounts as prefix+tenant-local sequence, beginning 1001. Name may be omitted for generated accounts or existing externalId. Existing names, immutable codes, balances and histories never change when editing the prefix. This setting is not accepted by operator /player or /launch requests."
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "SeamlessBattle": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "buyInMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "scoreMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "prizeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "feeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "netPoolMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "totalPayoutMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "feeBps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "gameId": {
            "type": "string"
          },
          "gameIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gameName": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "bonusType": {
            "type": "string"
          },
          "bonusName": {
            "type": "string"
          },
          "outcome": {
            "enum": [
              "pending",
              "win",
              "tie",
              "loss",
              "refund"
            ]
          },
          "winners": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "competition": {
            "type": "object",
            "description": "Period metadata at the time the immutable wallet command was created. Entry fees reserve the round; prizes settle only after the period is finalized.",
            "properties": {
              "periodId": {
                "type": "string",
                "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "daily",
                  "weekly",
                  "monthly"
                ]
              },
              "status": {
                "type": "string"
              },
              "entryClosesAt": {
                "$ref": "#/components/schemas/EpochMilliseconds"
              },
              "endAt": {
                "$ref": "#/components/schemas/EpochMilliseconds"
              },
              "poolBasis": {
                "enum": [
                  "bonus",
                  "entry"
                ]
              },
              "prize": {
                "type": "integer",
                "format": "int64",
                "minimum": 0,
                "description": "Integer TRY minor units (kurus)."
              },
              "rank": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 1
              }
            }
          }
        },
        "description": "Immutable battle details. Game fields arrive after selection; completed settlement includes score,prize,fee,bonus and outcome. Unknown optional fields may be added."
      },
      "SeamlessRequest": {
        "type": "object",
        "required": [
          "version",
          "tenantId",
          "externalId",
          "requestId",
          "currency",
          "action"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "tenantId": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "requestId": {
            "type": "string",
            "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
          },
          "currency": {
            "const": "TRY"
          },
          "action": {
            "enum": [
              "balance",
              "reserve",
              "refund",
              "settle"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "holdReference": {
            "type": "string",
            "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
          },
          "battle": {
            "$ref": "#/components/schemas/SeamlessBattle"
          }
        },
        "additionalProperties": false,
        "description": "balance contains no amount/hold/battle. Reserve subtracts available and creates a hold. Refund closes and fully restores it. Settle atomically consumes the hold and credits prize, including0 for a loss. Refund/settle require reserve requestId as holdReference. Persist identical request bodies for idempotent retries."
      },
      "SeamlessResponse": {
        "type": "object",
        "required": [
          "version",
          "tenantId",
          "externalId",
          "requestId",
          "currency",
          "balance",
          "receipt"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "tenantId": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "requestId": {
            "type": "string",
            "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
          },
          "currency": {
            "const": "TRY"
          },
          "balance": {
            "type": "object",
            "required": [
              "availableMinor",
              "lockedMinor",
              "revision"
            ],
            "properties": {
              "availableMinor": {
                "type": "integer",
                "minimum": 0,
                "maximum": 1000000000000
              },
              "lockedMinor": {
                "type": "integer",
                "minimum": 0,
                "maximum": 1000000000000
              },
              "revision": {
                "type": "integer",
                "minimum": 0
              }
            }
          },
          "receipt": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "id",
                  "requestId",
                  "action",
                  "amountMinor",
                  "holdReference",
                  "battleId",
                  "createdAt"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "requestId": {
                    "type": "string",
                    "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
                  },
                  "action": {
                    "enum": [
                      "reserve",
                      "refund",
                      "settle"
                    ]
                  },
                  "amountMinor": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000000000000
                  },
                  "holdReference": {
                    "type": "string",
                    "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
                  },
                  "battleId": {
                    "type": "string"
                  },
                  "createdAt": {
                    "type": "integer",
                    "minimum": 0
                  }
                }
              }
            ]
          }
        },
        "description": "Receipt is immutable, balance is CURRENT on retry. Lower balance revisions must never replace a newer cache. Every response, including a definitive failure, is signed and bound to request identity."
      },
      "SeamlessError": {
        "type": "object",
        "required": [
          "version",
          "tenantId",
          "externalId",
          "requestId",
          "currency",
          "error",
          "code"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "tenantId": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "requestId": {
            "type": "string",
            "pattern": "^[-A-Za-z0-9_.:@]{8,160}$"
          },
          "currency": {
            "const": "TRY"
          },
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        },
        "description": "Signed matching4xx (except408/429) is definitive. Timeout, invalid signature, identity mismatch,5xx,408/429 remain unresolved and retry the same requestId."
      },
      "TenantBranding": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "accentColor": {
            "type": "string",
            "pattern": "^#[0-9A-Fa-f]{6}$"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "accentColor"
        ],
        "additionalProperties": false
      },
      "PlayerDeviceContext": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "deviceId": {
            "type": "string",
            "pattern": "^[-a-zA-Z0-9]{16,80}$",
            "description": "Random origin-scoped browser identifier. Stored server-side only as a keyed hash; client-supplied and resettable, not proof of device ownership."
          },
          "roomId": {
            "type": "string",
            "pattern": "^(?:[a-f0-9]{10})?$",
            "description": "Only an existing member of the room can attach room-scoped evidence. Otherwise stored as generic session context."
          },
          "timezone": {
            "type": "string",
            "maxLength": 100
          },
          "language": {
            "type": "string",
            "maxLength": 64
          },
          "platform": {
            "type": "string",
            "maxLength": 120
          },
          "screenWidth": {
            "type": "integer",
            "minimum": 0,
            "maximum": 32768
          },
          "screenHeight": {
            "type": "integer",
            "minimum": 0,
            "maximum": 32768
          },
          "touchPoints": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "pixelRatio": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 20
          }
        }
      },
      "ChatSetting": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string"
          },
          "tenantName": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          }
        },
        "required": [
          "tenantId",
          "tenantName",
          "enabled"
        ]
      },
      "ChatRestriction": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string"
          },
          "tenantName": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "publicId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "warned",
              "timeout",
              "banned"
            ]
          },
          "strikes": {
            "type": "integer"
          },
          "until": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "automatic",
              "staff",
              null
            ]
          },
          "actorName": {
            "type": [
              "string",
              "null"
            ]
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          }
        }
      },
      "ChatMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "string",
              "integer"
            ]
          },
          "tenantId": {
            "type": "string"
          },
          "tenantName": {
            "type": "string"
          },
          "roomId": {
            "type": "string"
          },
          "channel": {
            "enum": [
              "room",
              "tribune"
            ]
          },
          "userId": {
            "type": "string"
          },
          "publicId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Canonical Arena Battle public alias, never the operator private username."
          },
          "message": {
            "type": "string"
          },
          "createdAt": {
            "type": "integer"
          },
          "restriction": {
            "$ref": "#/components/schemas/ChatRestriction"
          }
        }
      },
      "ChatEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "tenantId": {
            "type": "string"
          },
          "tenantName": {
            "type": "string"
          },
          "userId": {
            "type": [
              "string",
              "null"
            ]
          },
          "publicId": {
            "type": [
              "string",
              "null"
            ]
          },
          "roomId": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "enum": [
              "violation",
              "ban",
              "timeout",
              "unban",
              "setting"
            ]
          },
          "reason": {
            "type": "string"
          },
          "excerpt": {
            "type": "string"
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "strikes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "until": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          },
          "actorName": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "integer"
          }
        }
      },
      "ChatModerationFeed": {
        "type": "object",
        "properties": {
          "settings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatSetting"
            }
          },
          "policy": {
            "type": "object",
            "properties": {
              "warningCount": {
                "const": 2
              },
              "timeouts": {
                "type": "array",
                "items": {
                  "type": "integer"
                },
                "examples": [
                  [
                    10,
                    60
                  ]
                ]
              },
              "permanentAt": {
                "const": 5
              },
              "chatLimit": {
                "const": 5
              },
              "reactionLimit": {
                "const": 12
              },
              "windowSeconds": {
                "const": 10
              }
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "messages": {
                "type": "integer"
              },
              "violations": {
                "type": "integer"
              },
              "timeouts": {
                "type": "integer"
              },
              "banned": {
                "type": "integer"
              }
            }
          },
          "messages": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "restrictions": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "$ref": "#/components/schemas/ChatRestriction"
            }
          },
          "events": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "$ref": "#/components/schemas/ChatEvent"
            }
          },
          "serverTime": {
            "type": "integer"
          }
        },
        "required": [
          "settings",
          "policy",
          "summary",
          "messages",
          "restrictions",
          "events",
          "serverTime"
        ],
        "description": "Latest bounded scoped records. Summary counters are not lifetime totals and can include more scoped records than the final merged 300-row feeds."
      },
      "PlayerChatModeration": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "canSend": {
            "type": "boolean"
          },
          "blocked": {
            "type": "boolean"
          },
          "status": {
            "enum": [
              "active",
              "warned",
              "timeout",
              "banned",
              "disabled"
            ]
          },
          "strikes": {
            "type": "integer"
          },
          "until": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Unix milliseconds, or null."
          },
          "publicId": {
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": "string"
          },
          "messageEn": {
            "type": "string"
          },
          "serverTime": {
            "type": "integer"
          }
        },
        "required": [
          "enabled",
          "canSend",
          "blocked",
          "status",
          "strikes",
          "until",
          "expiresAt",
          "publicId",
          "message",
          "messageEn",
          "serverTime"
        ],
        "description": "Public status contains no staff note/name. Site disable affects its source-site players even in shared rooms; restrictions do not alter games or wallets."
      },
      "ChatOperationKey": {
        "type": "string",
        "pattern": "^[-A-Za-z0-9_]{8,80}$",
        "description": "Reuse the same key and payload on network retries. Never automatically retry rejected content with fresh keys."
      },
      "ChatSettingInput": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "enabled"
        ],
        "additionalProperties": false
      },
      "ChatModerateInput": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "tenantId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "action": {
                "enum": [
                  "ban",
                  "unban"
                ]
              },
              "reason": {
                "type": "string",
                "minLength": 5,
                "maxLength": 500
              }
            },
            "required": [
              "userId",
              "action",
              "reason"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "tenantId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "action": {
                "const": "timeout"
              },
              "reason": {
                "type": "string",
                "minLength": 5,
                "maxLength": 500
              },
              "minutes": {
                "enum": [
                  10,
                  60,
                  1440
                ]
              }
            },
            "required": [
              "userId",
              "action",
              "reason",
              "minutes"
            ],
            "additionalProperties": false
          }
        ],
        "description": "Provider staff must specify tenantId. Site staff may omit it or supply only their own. Reason is trimmed and must not contain control characters. Unban clears accumulated strikes."
      },
      "PlayerSocialFeed": {
        "type": "object",
        "properties": {
          "roomId": {
            "type": "string"
          },
          "channel": {
            "enum": [
              "room",
              "tribune"
            ]
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "cursor": {
            "type": "integer"
          },
          "moderation": {
            "$ref": "#/components/schemas/PlayerChatModeration"
          },
          "reactions": {
            "type": "object",
            "properties": {
              "visible": {
                "type": "array",
                "maxItems": 6,
                "items": {
                  "type": "object"
                }
              },
              "overflow": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "allowed": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "rematch": {}
        },
        "required": [
          "roomId",
          "channel",
          "messages",
          "cursor",
          "moderation",
          "reactions"
        ]
      },
      "CatalogResponse": {
        "type": "object",
        "required": [
          "games",
          "currency",
          "environment"
        ],
        "properties": {
          "games": {
            "type": "array",
            "description": "Only games and bonus choices enabled for this site. buyAmounts are exact integer minor-unit quotes.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "currency": {
            "type": "string",
            "enum": [
              "TRY"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "sandbox"
            ]
          }
        }
      },
      "RoomsResponse": {
        "type": "object",
        "required": [
          "rooms"
        ],
        "properties": {
          "rooms": {
            "type": "array",
            "description": "Visible rooms for this tenant. A completed room may still have settlementStatus=pending.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "StatisticsResponse": {
        "type": "object",
        "required": [
          "statistics"
        ],
        "properties": {
          "statistics": {
            "type": "object",
            "description": "Tenant-scoped finance/operations report; entry volume and wallet transfers are not profit.",
            "additionalProperties": true
          }
        }
      },
      "PeriodLedgerContext": {
        "type": "object",
        "properties": {
          "periodId": {
            "type": "string",
            "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "entryId": {
            "type": "string"
          },
          "entryStatus": {
            "type": "string"
          },
          "periodStatus": {
            "type": "string"
          },
          "gameId": {
            "type": "string"
          },
          "gameName": {
            "type": "string"
          },
          "buyInMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "scoreMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "prizeMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          }
        },
        "required": [
          "periodId",
          "kind",
          "entryId",
          "entryStatus",
          "periodStatus",
          "gameId",
          "gameName",
          "buyInMinor",
          "scoreMinor",
          "prizeMinor",
          "rank"
        ],
        "additionalProperties": false,
        "description": "Optional current period context on an immutable ledger event. This context can change as the period progresses; use the event ID/cursor and amountMinor for reconciliation, never credit a wallet from this context."
      },
      "SitePeriodSummary": {
        "type": "object",
        "properties": {
          "participants": {
            "type": "integer",
            "minimum": 0
          },
          "completed": {
            "type": "integer",
            "minimum": 0
          },
          "inProgress": {
            "type": "integer",
            "minimum": 0
          },
          "voided": {
            "type": "integer",
            "minimum": 0
          },
          "winners": {
            "type": "integer",
            "minimum": 0
          },
          "entryVolume": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "totalScores": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "awardedPrizes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "paidPrizes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "pendingPrizes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "refunds": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "pendingRefunds": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "commission": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "providerRevenue": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "operatorShare": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          }
        },
        "required": [
          "participants",
          "completed",
          "inProgress",
          "voided",
          "winners",
          "entryVolume",
          "totalScores",
          "awardedPrizes",
          "paidPrizes",
          "pendingPrizes",
          "refunds",
          "pendingRefunds",
          "commission",
          "providerRevenue",
          "operatorShare"
        ],
        "additionalProperties": false,
        "description": "Whole selected-period totals for the authenticated site, independent of pagination. Entry volume includes cancelled entries; refunds are separate. Paid amounts require wallet acknowledgement. Scores and entry volume are not operator revenue."
      },
      "PeriodHeader": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "startAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "endAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "kind",
          "startAt",
          "endAt",
          "status"
        ],
        "additionalProperties": false
      },
      "SitePeriod": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^(daily|weekly|monthly)-[0-9]{13}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "startAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "endAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "status": {
            "type": "string"
          },
          "entryClosesAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "settledAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "timeZone": {
            "const": "Europe/Istanbul"
          },
          "buyIn": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "feeBps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "poolBasis": {
            "enum": [
              "bonus",
              "entry"
            ]
          },
          "shares": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000
            }
          },
          "game": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": true
          },
          "bonus": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "kind",
          "startAt",
          "endAt",
          "status",
          "entryClosesAt",
          "settledAt",
          "timeZone",
          "buyIn",
          "feeBps",
          "poolBasis",
          "shares",
          "game",
          "bonus"
        ],
        "additionalProperties": false,
        "description": "Public configuration snapshot. It contains no other-site player identities or site totals. Monetary fields are TRY minor units; feeBps and shares are basis points."
      },
      "SitePeriodEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "publicId": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "externalId": {
            "type": [
              "string",
              "null"
            ]
          },
          "siteUsername": {
            "type": [
              "string",
              "null"
            ]
          },
          "roomId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "roomStatus": {
            "type": "string"
          },
          "enteredAt": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          },
          "buyIn": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "score": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "prize": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "paidPrize": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "refund": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "paymentStatus": {
            "enum": [
              "awaiting-period",
              "pending",
              "complete",
              "refunded",
              "refund-pending"
            ]
          },
          "commission": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "providerRevenue": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          },
          "operatorShare": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Integer TRY minor units (kurus)."
          }
        },
        "required": [
          "id",
          "userId",
          "publicId",
          "name",
          "externalId",
          "siteUsername",
          "roomId",
          "status",
          "roomStatus",
          "enteredAt",
          "buyIn",
          "score",
          "rank",
          "prize",
          "paidPrize",
          "refund",
          "paymentStatus",
          "commission",
          "providerRevenue",
          "operatorShare"
        ],
        "additionalProperties": false,
        "description": "Private identity fields belong only to the authenticated site. Rank is global and provisional before settlement. A bonus score is not an immediately paid prize."
      },
      "SitePeriodReport": {
        "type": "object",
        "properties": {
          "scope": {
            "const": "authenticated-site"
          },
          "tenantId": {
            "type": "string"
          },
          "currency": {
            "const": "TRY"
          },
          "amountUnit": {
            "const": "minor"
          },
          "kind": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "periods": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/PeriodHeader"
            }
          },
          "period": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SitePeriod"
              },
              {
                "type": "null"
              }
            ]
          },
          "summary": {
            "$ref": "#/components/schemas/SitePeriodSummary"
          },
          "entries": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/SitePeriodEntry"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "offset": {
                "type": "integer",
                "minimum": 0
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              },
              "total": {
                "type": "integer",
                "minimum": 0
              },
              "hasMore": {
                "type": "boolean"
              }
            },
            "required": [
              "offset",
              "limit",
              "total",
              "hasMore"
            ],
            "additionalProperties": false
          },
          "serverTime": {
            "$ref": "#/components/schemas/EpochMilliseconds"
          }
        },
        "required": [
          "scope",
          "tenantId",
          "currency",
          "amountUnit",
          "kind",
          "periods",
          "period",
          "summary",
          "entries",
          "pagination",
          "serverTime"
        ],
        "additionalProperties": false
      },
      "BillingLine": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 250
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          }
        },
        "required": [
          "description",
          "amountMinor"
        ]
      },
      "BillingDraft": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "tenantId": {
            "type": "string"
          },
          "period": {
            "type": "string",
            "pattern": "^20[0-9]{2}-(0[1-9]|1[0-2])$"
          },
          "reference": {
            "type": "string",
            "minLength": 8,
            "maxLength": 120
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/BillingLine"
            }
          },
          "note": {
            "type": "string",
            "maxLength": 1000
          }
        },
        "required": [
          "tenantId",
          "period",
          "reference"
        ]
      },
      "BillingEdit": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/BillingLine"
            }
          },
          "note": {
            "type": "string",
            "maxLength": 1000
          }
        }
      },
      "BillingPayment": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amountMinor": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000000000
          },
          "reference": {
            "type": "string",
            "minLength": 8,
            "maxLength": 120
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "amountMinor",
          "reference"
        ]
      },
      "BillingSiteSettings": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "autoIssue": {
            "type": "boolean"
          },
          "emailEnabled": {
            "type": "boolean"
          },
          "remindersEnabled": {
            "type": "boolean"
          },
          "mode": {
            "enum": [
              "manual",
              "fixed",
              "provider_share_v1"
            ]
          },
          "fixedMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "invoiceDay": {
            "type": "integer",
            "minimum": 1,
            "maximum": 28
          },
          "dueDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90
          },
          "taxBps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "recipientName": {
            "type": "string",
            "maxLength": 160
          },
          "recipientAddress": {
            "type": "string",
            "maxLength": 400
          },
          "recipientTaxId": {
            "type": "string",
            "maxLength": 80
          },
          "email": {
            "type": "string",
            "maxLength": 254
          },
          "locale": {
            "enum": [
              "tr",
              "en"
            ]
          }
        }
      },
      "BillingGlobalSettings": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "emailEnabled": {
            "type": "boolean"
          },
          "issuerName": {
            "type": "string",
            "maxLength": 160
          },
          "issuerAddress": {
            "type": "string",
            "maxLength": 400
          },
          "issuerTaxId": {
            "type": "string",
            "maxLength": 80
          },
          "paymentInstructions": {
            "type": "string",
            "maxLength": 1000
          },
          "documentLabel": {
            "type": "string",
            "maxLength": 100
          }
        }
      },
      "BillingVoid": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "reason": {
            "type": "string",
            "minLength": 5,
            "maxLength": 500
          }
        },
        "required": [
          "reason"
        ]
      },
      "BillingEmail": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "retryId": {
            "type": "string"
          }
        }
      },
      "EmptyObject": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "SiteRiskThresholds": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "highMultiplier": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          },
          "highPayoutMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "repeatedOpponents": {
            "type": "integer",
            "minimum": 2,
            "maximum": 1000
          },
          "historyWindowHours": {
            "type": "integer",
            "minimum": 1,
            "maximum": 720
          },
          "winRateMinimumBattles": {
            "type": "integer",
            "minimum": 3,
            "maximum": 1000
          },
          "winRatePercent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "winRateMinReturnBps": {
            "type": "integer",
            "minimum": 10000,
            "maximum": 100000000
          },
          "rapidJoinCount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000
          },
          "rapidWindowMinutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1440
          },
          "activeRoomLimit": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "apiErrorRate": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "apiErrorMinimum": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          },
          "waitingMinutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 43200
          },
          "sameIp": {
            "type": "boolean"
          },
          "sameDevice": {
            "type": "boolean"
          },
          "winRateEnabled": {
            "type": "boolean"
          }
        }
      },
      "SiteRiskUpdate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "rules": {
            "$ref": "#/components/schemas/SiteRiskThresholds"
          },
          "reset": {
            "type": "boolean",
            "enum": [
              true
            ]
          }
        }
      },
      "PanelLanguagePreference": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "locale": {
            "type": "string",
            "enum": [
              "tr",
              "en"
            ]
          }
        },
        "required": [
          "locale"
        ]
      }
    },
    "responses": {
      "Error400": {
        "description": "Invalid fields, encoding, identifier, amount, origin or idempotency header.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error401": {
        "description": "API key missing, invalid, expired or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error403": {
        "description": "Required key scope/IP restriction denied; browser Origin header forbidden on server-only APIs.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error404": {
        "description": "Player or original transfer reference does not exist in this API key tenant.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error409": {
        "description": "Insufficient available funds, conflicting immutable reference or account limit. Do not automatically compensate an unknown outcome.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error429": {
        "description": "Rate limited; back off and retry the same immutable request/cursor.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error503": {
        "description": "New participation or credit paused, maintenance or provider unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "operatorWallet": {
      "post": {
        "operationId": "operatorAuthoritativeWallet",
        "summary": "Provider calls the configured operator-owned wallet URL",
        "security": [
          {
            "WalletSignature": [],
            "WalletTimestamp": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SeamlessRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed exact receipt and current authoritative balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SeamlessResponse"
                }
              }
            }
          },
          "4XX": {
            "description": "Signed request-bound rejection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SeamlessError"
                }
              }
            }
          },
          "5XX": {
            "description": "Unresolved; durable retry uses same request identity"
          }
        }
      }
    }
  }
}
