{"info":{"_postman_id":"cff87b0a-f239-4ae5-b249-3a4236af4508","name":"Integration API","description":"<html><head></head><body><h2 id=\"changelog\">Changelog</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Version</th>\n<th>Date</th>\n<th>Changes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1.0</td>\n<td>2024-03-19</td>\n<td>Initial version</td>\n</tr>\n<tr>\n<td>2.0</td>\n<td>2024-09-30</td>\n<td>Free Spins support &amp; Model update</td>\n</tr>\n<tr>\n<td>2.1</td>\n<td>2024-10-11</td>\n<td>Refactor value formats</td>\n</tr>\n<tr>\n<td>3.0</td>\n<td>2024-11-06</td>\n<td>Lobby support</td>\n</tr>\n<tr>\n<td>3.1</td>\n<td>2024-11-18</td>\n<td>Game Round History support</td>\n</tr>\n<tr>\n<td>3.2</td>\n<td>2025-01-13</td>\n<td>Get Providers support</td>\n</tr>\n<tr>\n<td>3.3</td>\n<td>2025-02-14</td>\n<td>Refactor types &amp; Update description</td>\n</tr>\n<tr>\n<td>3.4</td>\n<td>2025-04-02</td>\n<td>Added non-game transactions support</td>\n</tr>\n<tr>\n<td>3.5</td>\n<td>2025-06-04</td>\n<td>Game providerGameId support &amp; Transaction providerRoundId support</td>\n</tr>\n<tr>\n<td>3.6</td>\n<td>2025-06-24</td>\n<td>Update supported currencies</td>\n</tr>\n<tr>\n<td>3.7</td>\n<td>2025-07-31</td>\n<td>Add brand id support</td>\n</tr>\n<tr>\n<td>3.8</td>\n<td>2025-09-11</td>\n<td>Remove brand support</td>\n</tr>\n<tr>\n<td>3.9</td>\n<td>2025-09-29</td>\n<td>Add multi-currency support &amp; Get Player Details support</td>\n</tr>\n<tr>\n<td>3.10</td>\n<td>2025-10-01</td>\n<td>Affiliate support</td>\n</tr>\n<tr>\n<td>3.11</td>\n<td>2025-10-10</td>\n<td>Free Spins Completed</td>\n</tr>\n<tr>\n<td>3.12</td>\n<td>2025-11-08</td>\n<td>Session mechanism</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"introduction\">Introduction</h2>\n<p>Casino is the entity which works with the players.<br>Aggregator Provider is the entity which provides single API for integrations.</p>\n<p>Casino provides:</p>\n<ol>\n<li><p>Callback Url</p>\n</li>\n<li><p>IPs to whitelist.</p>\n</li>\n</ol>\n<p>Aggregator Provider provides:</p>\n<ol>\n<li><p>API Url</p>\n</li>\n<li><p>Basic Auth Username</p>\n</li>\n<li><p>Basic Auth Password</p>\n</li>\n<li><p>Brand Id</p>\n</li>\n<li><p>IPs to whitelist.</p>\n</li>\n</ol>\n<hr>\n<h2 id=\"formats\">Formats</h2>\n<h4 id=\"money\">Money</h4>\n<p>Money amount is passed with minor units<br>Examples: 2.50 EUR = 250, 10.50 TRY = 1050</p>\n<p>Currency is passed as string<br>Examples: EUR, TRY</p>\n<p>Supported Currencies:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><strong>Currency</strong></th>\n<th><strong>Name</strong></th>\n<th><strong>Minor Units</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>AED</td>\n<td>United Arab Emirates Dirham</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ALL</td>\n<td>Albanian Lek</td>\n<td>2</td>\n</tr>\n<tr>\n<td>AMD</td>\n<td>Armenian Dram</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ANG</td>\n<td>Netherlands Antillean Guilder</td>\n<td>2</td>\n</tr>\n<tr>\n<td>AOA</td>\n<td>Angolan Kwanza</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ARS</td>\n<td>Argentine Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>AUD</td>\n<td>Australian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>AWG</td>\n<td>Aruban Florin</td>\n<td>2</td>\n</tr>\n<tr>\n<td>AZN</td>\n<td>Azerbaijani Manat</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BAM</td>\n<td>Bosnia-Herzegovina Convertible Mark</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BBD</td>\n<td>Barbadian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BDT</td>\n<td>Bangladeshi Taka</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BGN</td>\n<td>Bulgarian Lev</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BHD</td>\n<td>Bahraini Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>BIF</td>\n<td>Burundian Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>BMD</td>\n<td>Bermudian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BND</td>\n<td>Brunei Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BOB</td>\n<td>Bolivian Boliviano</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BOV</td>\n<td>Bolivian Mvdol</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BRL</td>\n<td>Brazilian Real</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BSD</td>\n<td>Bahamian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BTN</td>\n<td>Bhutanese Ngultrum</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BWP</td>\n<td>Botswanan Pula</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BYN</td>\n<td>Belarusian Ruble</td>\n<td>2</td>\n</tr>\n<tr>\n<td>BZD</td>\n<td>Belize Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CAD</td>\n<td>Canadian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CDF</td>\n<td>Congolese Franc</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CHE</td>\n<td>WIR Euro</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CHF</td>\n<td>Swiss Franc</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CHW</td>\n<td>WIR Franc</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CLF</td>\n<td>Unidad de Fomento (Chile)</td>\n<td>4</td>\n</tr>\n<tr>\n<td>CLP</td>\n<td>Chilean Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CNY</td>\n<td>Chinese Yuan</td>\n<td>2</td>\n</tr>\n<tr>\n<td>COP</td>\n<td>Colombian Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>COU</td>\n<td>Unidad de Valor Real</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CRC</td>\n<td>Costa Rican Colón</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CUC</td>\n<td>Cuban Convertible Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CUP</td>\n<td>Cuban Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CVE</td>\n<td>Cape Verdean Escudo</td>\n<td>2</td>\n</tr>\n<tr>\n<td>CZK</td>\n<td>Czech Koruna</td>\n<td>2</td>\n</tr>\n<tr>\n<td>DJF</td>\n<td>Djiboutian Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>DKK</td>\n<td>Danish Krone</td>\n<td>2</td>\n</tr>\n<tr>\n<td>DOP</td>\n<td>Dominican Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>DZD</td>\n<td>Algerian Dinar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>EGP</td>\n<td>Egyptian Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ERN</td>\n<td>Eritrean Nakfa</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ETB</td>\n<td>Ethiopian Birr</td>\n<td>2</td>\n</tr>\n<tr>\n<td>EUR</td>\n<td>Euro</td>\n<td>2</td>\n</tr>\n<tr>\n<td>FJD</td>\n<td>Fijian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>FKP</td>\n<td>Falkland Islands Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GBP</td>\n<td>British Pound Sterling</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GEL</td>\n<td>Georgian Lari</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GHS</td>\n<td>Ghanaian Cedi</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GIP</td>\n<td>Gibraltar Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GMD</td>\n<td>Gambian Dalasi</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GNF</td>\n<td>Guinean Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>GTQ</td>\n<td>Guatemalan Quetzal</td>\n<td>2</td>\n</tr>\n<tr>\n<td>GYD</td>\n<td>Guyanaese Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>HKD</td>\n<td>Hong Kong Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>HNL</td>\n<td>Honduran Lempira</td>\n<td>2</td>\n</tr>\n<tr>\n<td>HRK</td>\n<td>Croatian Kuna</td>\n<td>2</td>\n</tr>\n<tr>\n<td>HTG</td>\n<td>Haitian Gourde</td>\n<td>2</td>\n</tr>\n<tr>\n<td>HUF</td>\n<td>Hungarian Forint</td>\n<td>2</td>\n</tr>\n<tr>\n<td>IDR</td>\n<td>Indonesian Rupiah</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ILS</td>\n<td>Israeli New Shekel</td>\n<td>2</td>\n</tr>\n<tr>\n<td>INR</td>\n<td>Indian Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>IQD</td>\n<td>Iraqi Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>IRR</td>\n<td>Iranian Rial</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ISK</td>\n<td>Icelandic Króna</td>\n<td>0</td>\n</tr>\n<tr>\n<td>JMD</td>\n<td>Jamaican Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>JOD</td>\n<td>Jordanian Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>JPY</td>\n<td>Japanese Yen</td>\n<td>0</td>\n</tr>\n<tr>\n<td>KES</td>\n<td>Kenyan Shilling</td>\n<td>2</td>\n</tr>\n<tr>\n<td>KGS</td>\n<td>Kyrgyzstani Som</td>\n<td>2</td>\n</tr>\n<tr>\n<td>KHR</td>\n<td>Cambodian Riel</td>\n<td>2</td>\n</tr>\n<tr>\n<td>KMF</td>\n<td>Comorian Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>KPW</td>\n<td>North Korean Won</td>\n<td>2</td>\n</tr>\n<tr>\n<td>KRW</td>\n<td>South Korean Won</td>\n<td>0</td>\n</tr>\n<tr>\n<td>KWD</td>\n<td>Kuwaiti Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>KYD</td>\n<td>Cayman Islands Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>KZT</td>\n<td>Kazakhstani Tenge</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LAK</td>\n<td>Lao Kip</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LBP</td>\n<td>Lebanese Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LKR</td>\n<td>Sri Lankan Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LRD</td>\n<td>Liberian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LSL</td>\n<td>Lesotho Loti</td>\n<td>2</td>\n</tr>\n<tr>\n<td>LYD</td>\n<td>Libyan Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>MAD</td>\n<td>Moroccan Dirham</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MDL</td>\n<td>Moldovan Leu</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MGA</td>\n<td>Malagasy Ariary</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MKD</td>\n<td>Macedonian Denar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MMK</td>\n<td>Myanmar Kyat</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MNT</td>\n<td>Mongolian Tögrög</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MOP</td>\n<td>Macanese Pataca</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MRU</td>\n<td>Mauritanian Ouguiya</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MUR</td>\n<td>Mauritian Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MVR</td>\n<td>Maldivian Rufiyaa</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MWK</td>\n<td>Malawian Kwacha</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MXN</td>\n<td>Mexican Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MXV</td>\n<td>Mexican Unidad de Inversion</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MYR</td>\n<td>Malaysian Ringgit</td>\n<td>2</td>\n</tr>\n<tr>\n<td>MZN</td>\n<td>Mozambican Metical</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NAD</td>\n<td>Namibian Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NGN</td>\n<td>Nigerian Naira</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NIO</td>\n<td>Nicaraguan Córdoba</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NOK</td>\n<td>Norwegian Krone</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NPR</td>\n<td>Nepalese Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>NZD</td>\n<td>New Zealand Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>OMR</td>\n<td>Omani Rial</td>\n<td>3</td>\n</tr>\n<tr>\n<td>PAB</td>\n<td>Panamanian Balboa</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PEN</td>\n<td>Peruvian Sol</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PGK</td>\n<td>Papua New Guinean Kina</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PHP</td>\n<td>Philippine Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PKR</td>\n<td>Pakistani Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PLN</td>\n<td>Polish Złoty</td>\n<td>2</td>\n</tr>\n<tr>\n<td>PYG</td>\n<td>Paraguayan Guaraní</td>\n<td>0</td>\n</tr>\n<tr>\n<td>QAR</td>\n<td>Qatari Riyal</td>\n<td>2</td>\n</tr>\n<tr>\n<td>RON</td>\n<td>Romanian Leu</td>\n<td>2</td>\n</tr>\n<tr>\n<td>RSD</td>\n<td>Serbian Dinar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>RUB</td>\n<td>Russian Ruble</td>\n<td>2</td>\n</tr>\n<tr>\n<td>RWF</td>\n<td>Rwandan Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>SAR</td>\n<td>Saudi Riyal</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SBD</td>\n<td>Solomon Islands Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SCR</td>\n<td>Seychellois Rupee</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SDG</td>\n<td>Sudanese Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SEK</td>\n<td>Swedish Krona</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SGD</td>\n<td>Singapore Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SHP</td>\n<td>Saint Helena Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SLL</td>\n<td>Sierra Leonean Leone</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SOS</td>\n<td>Somali Shilling</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SRD</td>\n<td>Surinamese Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SSP</td>\n<td>South Sudanese Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>STN</td>\n<td>São Tomé and Príncipe Dobra</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SVC</td>\n<td>Salvadoran Colón</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SYP</td>\n<td>Syrian Pound</td>\n<td>2</td>\n</tr>\n<tr>\n<td>SZL</td>\n<td>Swazi Lilangeni</td>\n<td>2</td>\n</tr>\n<tr>\n<td>THB</td>\n<td>Thai Baht</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TJS</td>\n<td>Tajikistani Somoni</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TMT</td>\n<td>Turkmenistani Manat</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TND</td>\n<td>Tunisian Dinar</td>\n<td>3</td>\n</tr>\n<tr>\n<td>TOP</td>\n<td>Tongan Paʻanga</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TRY</td>\n<td>Turkish Lira</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TTD</td>\n<td>Trinidad and Tobago Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TWD</td>\n<td>New Taiwan Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>TZS</td>\n<td>Tanzanian Shilling</td>\n<td>2</td>\n</tr>\n<tr>\n<td>UAH</td>\n<td>Ukrainian Hryvnia</td>\n<td>2</td>\n</tr>\n<tr>\n<td>UGX</td>\n<td>Ugandan Shilling</td>\n<td>0</td>\n</tr>\n<tr>\n<td>USD</td>\n<td>United States Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>USN</td>\n<td>US Dollar (Next day)</td>\n<td>2</td>\n</tr>\n<tr>\n<td>UYI</td>\n<td>Uruguay Peso en Unidades Indexadas</td>\n<td>0</td>\n</tr>\n<tr>\n<td>UYU</td>\n<td>Uruguayan Peso</td>\n<td>2</td>\n</tr>\n<tr>\n<td>UZS</td>\n<td>Uzbekistani Som</td>\n<td>2</td>\n</tr>\n<tr>\n<td>VND</td>\n<td>Vietnamese Đồng</td>\n<td>0</td>\n</tr>\n<tr>\n<td>VUV</td>\n<td>Vanuatu Vatu</td>\n<td>0</td>\n</tr>\n<tr>\n<td>WST</td>\n<td>Samoan Tala</td>\n<td>2</td>\n</tr>\n<tr>\n<td>XAF</td>\n<td>Central African CFA Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XCD</td>\n<td>East Caribbean Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>XOF</td>\n<td>West African CFA Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XPF</td>\n<td>CFP Franc</td>\n<td>0</td>\n</tr>\n<tr>\n<td>YER</td>\n<td>Yemeni Rial</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ZAR</td>\n<td>South African Rand</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ZMW</td>\n<td>Zambian Kwacha</td>\n<td>2</td>\n</tr>\n<tr>\n<td>ZWL</td>\n<td>Zimbabwean Dollar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>VEF</td>\n<td>Venezuelan Bolívar</td>\n<td>2</td>\n</tr>\n<tr>\n<td>XAG</td>\n<td>Silver (troy ounce)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XAU</td>\n<td>Gold (troy ounce)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XBA</td>\n<td>European Composite Unit</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XBB</td>\n<td>European Monetary Unit</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XBC</td>\n<td>European Unit of Account 9</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XBD</td>\n<td>European Unit of Account 17</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XDR</td>\n<td>Special Drawing Rights</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XPD</td>\n<td>Palladium (troy ounce)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XPT</td>\n<td>Platinum (troy ounce)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XSU</td>\n<td>SUCRE</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XTS</td>\n<td>Code Reserved for Testing</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XUA</td>\n<td>ADB Unit of Account</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XXX</td>\n<td>No Currency</td>\n<td>0</td>\n</tr>\n<tr>\n<td>XBT</td>\n<td>Bitcoin</td>\n<td>8</td>\n</tr>\n<tr>\n<td>BTC</td>\n<td>Bitcoin</td>\n<td>8</td>\n</tr>\n<tr>\n<td>ADA</td>\n<td>Cardano</td>\n<td>6</td>\n</tr>\n<tr>\n<td>BCH</td>\n<td>Bitcoin Cash</td>\n<td>8</td>\n</tr>\n<tr>\n<td>BNB</td>\n<td>Binance Coin</td>\n<td>18</td>\n</tr>\n<tr>\n<td>CRO</td>\n<td>Cronos</td>\n<td>18</td>\n</tr>\n<tr>\n<td>DAI</td>\n<td>Dai</td>\n<td>18</td>\n</tr>\n<tr>\n<td>DOGE</td>\n<td>Dogecoin</td>\n<td>8</td>\n</tr>\n<tr>\n<td>ETH</td>\n<td>Ethereum</td>\n<td>18</td>\n</tr>\n<tr>\n<td>LINK</td>\n<td>Chainlink</td>\n<td>18</td>\n</tr>\n<tr>\n<td>LTC</td>\n<td>Litecoin</td>\n<td>8</td>\n</tr>\n<tr>\n<td>POL</td>\n<td>Polygon</td>\n<td>18</td>\n</tr>\n<tr>\n<td>SAND</td>\n<td>The Sandbox</td>\n<td>18</td>\n</tr>\n<tr>\n<td>SOL</td>\n<td>Solana</td>\n<td>9</td>\n</tr>\n<tr>\n<td>TRX</td>\n<td>TRON</td>\n<td>6</td>\n</tr>\n<tr>\n<td>UNI</td>\n<td>Uniswap</td>\n<td>18</td>\n</tr>\n<tr>\n<td>USDC</td>\n<td>USD Coin</td>\n<td>6</td>\n</tr>\n<tr>\n<td>USDT</td>\n<td>Tether</td>\n<td>6</td>\n</tr>\n<tr>\n<td>XRP</td>\n<td>Ripple</td>\n<td>6</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h4 id=\"date-and-time\">Date And Time</h4>\n<p>Date and Time are passed in Unix Timestamp using UTC timezone (<a href=\"https://www.epochconverter.com/\">epochconverter</a>) - number of milliseconds from the epoch of 1970-01-01T00:00:00Z.<br>Examples: 2024-03-15T11:42:03+00:00 = '1710499323000'</p>\n<h4 id=\"locale\">Locale</h4>\n<p>User's locale should be passed in ISO-639 + '_' + ISO-3166 format (<a href=\"https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html\">ISO-639, ISO-3166</a>).</p>\n<p>Locales:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><strong>Locale</strong></th>\n<th><strong>Region</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>af_ZA</td>\n<td>Afrikaans (South Africa)</td>\n</tr>\n<tr>\n<td>ar_AR</td>\n<td>Arabic</td>\n</tr>\n<tr>\n<td>ar_AE</td>\n<td>Arabic (U.A.E.)</td>\n</tr>\n<tr>\n<td>ar_BH</td>\n<td>Arabic (Bahrain)</td>\n</tr>\n<tr>\n<td>ar_DZ</td>\n<td>Arabic (Algeria)</td>\n</tr>\n<tr>\n<td>ar_EG</td>\n<td>Arabic (Egypt)</td>\n</tr>\n<tr>\n<td>ar_IQ</td>\n<td>Arabic (Iraq)</td>\n</tr>\n<tr>\n<td>ar_JO</td>\n<td>Arabic (Jordan)</td>\n</tr>\n<tr>\n<td>ar_KW</td>\n<td>Arabic (Kuwait)</td>\n</tr>\n<tr>\n<td>ar_LB</td>\n<td>Arabic (Lebanon)</td>\n</tr>\n<tr>\n<td>ar_LY</td>\n<td>Arabic (Libya)</td>\n</tr>\n<tr>\n<td>ar_MA</td>\n<td>Arabic (Morocco)</td>\n</tr>\n<tr>\n<td>ar_OM</td>\n<td>Arabic (Oman)</td>\n</tr>\n<tr>\n<td>ar_QA</td>\n<td>Arabic (Qatar)</td>\n</tr>\n<tr>\n<td>ar_SA</td>\n<td>Arabic (Saudi Arabia)</td>\n</tr>\n<tr>\n<td>ar_SY</td>\n<td>Arabic (Syria)</td>\n</tr>\n<tr>\n<td>ar_TN</td>\n<td>Arabic (Tunisia)</td>\n</tr>\n<tr>\n<td>ar_YE</td>\n<td>Arabic (Yemen)</td>\n</tr>\n<tr>\n<td>az_AZ</td>\n<td>Azeri (Latin) (Azerbaijan)</td>\n</tr>\n<tr>\n<td>be_BY</td>\n<td>Belarusian (Belarus)</td>\n</tr>\n<tr>\n<td>bg_BG</td>\n<td>Bulgarian (Bulgaria)</td>\n</tr>\n<tr>\n<td>bs_BA</td>\n<td>Bosnian (Bosnia and Herzegovina)</td>\n</tr>\n<tr>\n<td>ca_ES</td>\n<td>Catalan (Spain)</td>\n</tr>\n<tr>\n<td>cs_CZ</td>\n<td>Czech (Czech Republic)</td>\n</tr>\n<tr>\n<td>cy_GB</td>\n<td>Welsh (United Kingdom)</td>\n</tr>\n<tr>\n<td>da_DK</td>\n<td>Danish (Denmark)</td>\n</tr>\n<tr>\n<td>de_AT</td>\n<td>German (Austria)</td>\n</tr>\n<tr>\n<td>de_CH</td>\n<td>German (Switzerland)</td>\n</tr>\n<tr>\n<td>de_DE</td>\n<td>German (Germany)</td>\n</tr>\n<tr>\n<td>de_LI</td>\n<td>German (Liechtenstein)</td>\n</tr>\n<tr>\n<td>de_LU</td>\n<td>German (Luxembourg)</td>\n</tr>\n<tr>\n<td>dv_MV</td>\n<td>Divehi (Maldives)</td>\n</tr>\n<tr>\n<td>el_GR</td>\n<td>Greek (Greece)</td>\n</tr>\n<tr>\n<td>el_EL</td>\n<td>Greek (Greece)</td>\n</tr>\n<tr>\n<td>en_AU</td>\n<td>English (Australia)</td>\n</tr>\n<tr>\n<td>en_BZ</td>\n<td>English (Belize)</td>\n</tr>\n<tr>\n<td>en_CA</td>\n<td>English (Canada)</td>\n</tr>\n<tr>\n<td>en_CB</td>\n<td>English (Caribbean)</td>\n</tr>\n<tr>\n<td>en_GB</td>\n<td>English (United Kingdom)</td>\n</tr>\n<tr>\n<td>en_IE</td>\n<td>English (Ireland)</td>\n</tr>\n<tr>\n<td>en_JM</td>\n<td>English (Jamaica)</td>\n</tr>\n<tr>\n<td>en_NZ</td>\n<td>English (New Zealand)</td>\n</tr>\n<tr>\n<td>en_PH</td>\n<td>English (Republic of the Philippines)</td>\n</tr>\n<tr>\n<td>en_TT</td>\n<td>English (Trinidad and Tobago)</td>\n</tr>\n<tr>\n<td>en_US</td>\n<td>English (United States)</td>\n</tr>\n<tr>\n<td>en_ZA</td>\n<td>English (South Africa)</td>\n</tr>\n<tr>\n<td>en_ZW</td>\n<td>English (Zimbabwe)</td>\n</tr>\n<tr>\n<td>es_AR</td>\n<td>Spanish (Argentina)</td>\n</tr>\n<tr>\n<td>es_BO</td>\n<td>Spanish (Bolivia)</td>\n</tr>\n<tr>\n<td>es_CL</td>\n<td>Spanish (Chile)</td>\n</tr>\n<tr>\n<td>es_CO</td>\n<td>Spanish (Colombia)</td>\n</tr>\n<tr>\n<td>es_CR</td>\n<td>Spanish (Costa Rica)</td>\n</tr>\n<tr>\n<td>es_DO</td>\n<td>Spanish (Dominican Republic)</td>\n</tr>\n<tr>\n<td>es_EC</td>\n<td>Spanish (Ecuador)</td>\n</tr>\n<tr>\n<td>es_ES</td>\n<td>Spanish (Spain)</td>\n</tr>\n<tr>\n<td>es_GT</td>\n<td>Spanish (Guatemala)</td>\n</tr>\n<tr>\n<td>es_HN</td>\n<td>Spanish (Honduras)</td>\n</tr>\n<tr>\n<td>es_MX</td>\n<td>Spanish (Mexico)</td>\n</tr>\n<tr>\n<td>es_NI</td>\n<td>Spanish (Nicaragua)</td>\n</tr>\n<tr>\n<td>es_PA</td>\n<td>Spanish (Panama)</td>\n</tr>\n<tr>\n<td>es_PE</td>\n<td>Spanish (Peru)</td>\n</tr>\n<tr>\n<td>es_PR</td>\n<td>Spanish (Puerto Rico)</td>\n</tr>\n<tr>\n<td>es_PY</td>\n<td>Spanish (Paraguay)</td>\n</tr>\n<tr>\n<td>es_SV</td>\n<td>Spanish (El Salvador)</td>\n</tr>\n<tr>\n<td>es_UY</td>\n<td>Spanish (Uruguay)</td>\n</tr>\n<tr>\n<td>es_VE</td>\n<td>Spanish (Venezuela)</td>\n</tr>\n<tr>\n<td>et_EE</td>\n<td>Estonian (Estonia)</td>\n</tr>\n<tr>\n<td>eu_ES</td>\n<td>Basque (Spain)</td>\n</tr>\n<tr>\n<td>fa_IR</td>\n<td>Farsi (Iran)</td>\n</tr>\n<tr>\n<td>fi_FI</td>\n<td>Finnish (Finland)</td>\n</tr>\n<tr>\n<td>fo_FO</td>\n<td>Faroese (Faroe Islands)</td>\n</tr>\n<tr>\n<td>fr_BE</td>\n<td>French (Belgium)</td>\n</tr>\n<tr>\n<td>fr_CA</td>\n<td>French (Canada)</td>\n</tr>\n<tr>\n<td>fr_CH</td>\n<td>French (Switzerland)</td>\n</tr>\n<tr>\n<td>fr_FR</td>\n<td>French (France)</td>\n</tr>\n<tr>\n<td>fr_LU</td>\n<td>French (Luxembourg)</td>\n</tr>\n<tr>\n<td>fr_MC</td>\n<td>French (Principality of Monaco)</td>\n</tr>\n<tr>\n<td>gl_ES</td>\n<td>Galician (Spain)</td>\n</tr>\n<tr>\n<td>gu_IN</td>\n<td>Gujarati (India)</td>\n</tr>\n<tr>\n<td>he_IL</td>\n<td>Hebrew (Israel)</td>\n</tr>\n<tr>\n<td>hi_IN</td>\n<td>Hindi (India)</td>\n</tr>\n<tr>\n<td>hr_BA</td>\n<td>Croatian (Bosnia and Herzegovina)</td>\n</tr>\n<tr>\n<td>hr_HR</td>\n<td>Croatian (Croatia)</td>\n</tr>\n<tr>\n<td>hu_HU</td>\n<td>Hungarian (Hungary)</td>\n</tr>\n<tr>\n<td>hy_AM</td>\n<td>Armenian (Armenia)</td>\n</tr>\n<tr>\n<td>id_ID</td>\n<td>Indonesian (Indonesia)</td>\n</tr>\n<tr>\n<td>is_IS</td>\n<td>Icelandic (Iceland)</td>\n</tr>\n<tr>\n<td>it_CH</td>\n<td>Italian (Switzerland)</td>\n</tr>\n<tr>\n<td>it_IT</td>\n<td>Italian (Italy)</td>\n</tr>\n<tr>\n<td>ja_JP</td>\n<td>Japanese (Japan)</td>\n</tr>\n<tr>\n<td>ka_GE</td>\n<td>Georgian (Georgia)</td>\n</tr>\n<tr>\n<td>kk_KZ</td>\n<td>Kazakh (Kazakhstan)</td>\n</tr>\n<tr>\n<td>kn_IN</td>\n<td>Kannada (India)</td>\n</tr>\n<tr>\n<td>ko_KR</td>\n<td>Korean (Korea)</td>\n</tr>\n<tr>\n<td>kok_IN</td>\n<td>Konkani (India)</td>\n</tr>\n<tr>\n<td>ky_KG</td>\n<td>Kyrgyz (Kyrgyzstan)</td>\n</tr>\n<tr>\n<td>lt_LT</td>\n<td>Lithuanian (Lithuania)</td>\n</tr>\n<tr>\n<td>lv_LV</td>\n<td>Latvian (Latvia)</td>\n</tr>\n<tr>\n<td>mi_NZ</td>\n<td>Maori (New Zealand)</td>\n</tr>\n<tr>\n<td>mk_MK</td>\n<td>FYRO Macedonian (Former Yugoslav Republic of Macedonia)</td>\n</tr>\n<tr>\n<td>mn_MN</td>\n<td>Mongolian (Mongolia)</td>\n</tr>\n<tr>\n<td>mr_IN</td>\n<td>Marathi (India)</td>\n</tr>\n<tr>\n<td>ms_BN</td>\n<td>Malay (Brunei Darussalam)</td>\n</tr>\n<tr>\n<td>ms_MY</td>\n<td>Malay (Malaysia)</td>\n</tr>\n<tr>\n<td>mt_MT</td>\n<td>Maltese (Malta)</td>\n</tr>\n<tr>\n<td>nb_NO</td>\n<td>Norwegian (Bokm?l) (Norway)</td>\n</tr>\n<tr>\n<td>nl_BE</td>\n<td>Dutch (Belgium)</td>\n</tr>\n<tr>\n<td>nl_NL</td>\n<td>Dutch (Netherlands)</td>\n</tr>\n<tr>\n<td>nn_NO</td>\n<td>Norwegian (Nynorsk) (Norway)</td>\n</tr>\n<tr>\n<td>ns_ZA</td>\n<td>Northern Sotho (South Africa)</td>\n</tr>\n<tr>\n<td>pa_IN</td>\n<td>Punjabi (India)</td>\n</tr>\n<tr>\n<td>pl_PL</td>\n<td>Polish (Poland)</td>\n</tr>\n<tr>\n<td>ps_AR</td>\n<td>Pashto (Afghanistan)</td>\n</tr>\n<tr>\n<td>pt_BR</td>\n<td>Portuguese (Brazil)</td>\n</tr>\n<tr>\n<td>pt_PT</td>\n<td>Portuguese (Portugal)</td>\n</tr>\n<tr>\n<td>qu_BO</td>\n<td>Quechua (Bolivia)</td>\n</tr>\n<tr>\n<td>qu_EC</td>\n<td>Quechua (Ecuador)</td>\n</tr>\n<tr>\n<td>qu_PE</td>\n<td>Quechua (Peru)</td>\n</tr>\n<tr>\n<td>ro_RO</td>\n<td>Romanian (Romania)</td>\n</tr>\n<tr>\n<td>ru_RU</td>\n<td>Russian (Russia)</td>\n</tr>\n<tr>\n<td>sa_IN</td>\n<td>Sanskrit (India)</td>\n</tr>\n<tr>\n<td>se_FI</td>\n<td>Sami (Northern) (Finland)</td>\n</tr>\n<tr>\n<td>se_NO</td>\n<td>Sami (Northern) (Norway)</td>\n</tr>\n<tr>\n<td>se_SE</td>\n<td>Sami (Northern) (Sweden)</td>\n</tr>\n<tr>\n<td>sk_SK</td>\n<td>Slovak (Slovakia)</td>\n</tr>\n<tr>\n<td>sl_SI</td>\n<td>Slovenian (Slovenia)</td>\n</tr>\n<tr>\n<td>sq_AL</td>\n<td>Albanian (Albania)</td>\n</tr>\n<tr>\n<td>sr_BA</td>\n<td>Serbian (Latin) (Bosnia and Herzegovina)</td>\n</tr>\n<tr>\n<td>sr_SP</td>\n<td>Serbian (Latin) (Serbia and Montenegro)</td>\n</tr>\n<tr>\n<td>sv_FI</td>\n<td>Swedish (Finland)</td>\n</tr>\n<tr>\n<td>sv_SE</td>\n<td>Swedish (Sweden)</td>\n</tr>\n<tr>\n<td>sw_KE</td>\n<td>Swahili (Kenya)</td>\n</tr>\n<tr>\n<td>syr_SY</td>\n<td>Syriac (Syria)</td>\n</tr>\n<tr>\n<td>ta_IN</td>\n<td>Tamil (India)</td>\n</tr>\n<tr>\n<td>te_IN</td>\n<td>Telugu (India)</td>\n</tr>\n<tr>\n<td>th_TH</td>\n<td>Thai (Thailand)</td>\n</tr>\n<tr>\n<td>tl_PH</td>\n<td>Tagalog (Philippines)</td>\n</tr>\n<tr>\n<td>tn_ZA</td>\n<td>Tswana (South Africa)</td>\n</tr>\n<tr>\n<td>tr_TR</td>\n<td>Turkish (Turkey)</td>\n</tr>\n<tr>\n<td>tt_RU</td>\n<td>Tatar (Russia)</td>\n</tr>\n<tr>\n<td>uk_UA</td>\n<td>Ukrainian (Ukraine)</td>\n</tr>\n<tr>\n<td>ur_PK</td>\n<td>Urdu (Islamic Republic of Pakistan)</td>\n</tr>\n<tr>\n<td>uz_UZ</td>\n<td>Uzbek (Latin) (Uzbekistan)</td>\n</tr>\n<tr>\n<td>vi_VN</td>\n<td>Vietnamese (Viet Nam)</td>\n</tr>\n<tr>\n<td>xh_ZA</td>\n<td>Xhosa (South Africa)</td>\n</tr>\n<tr>\n<td>zh_CN</td>\n<td>Chinese (S)</td>\n</tr>\n<tr>\n<td>zh_HK</td>\n<td>Chinese (Hong Kong)</td>\n</tr>\n<tr>\n<td>zh_MO</td>\n<td>Chinese (Macau)</td>\n</tr>\n<tr>\n<td>zh_SG</td>\n<td>Chinese (Singapore)</td>\n</tr>\n<tr>\n<td>zh_TW</td>\n<td>Chinese (T)</td>\n</tr>\n<tr>\n<td>zu_ZA</td>\n<td>Zulu (South Africa)</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2 id=\"security\">Security</h2>\n<p>Each request between casino and aggregator provider and vice versa must contain basic auth header (<a href=\"https://en.wikipedia.org/wiki/Basic_access_authentication\">Basic access authentication</a>)<br>Example for username 'name' and password 'password':<br>Authorization: Basic bmFtZTpwYXNzd29yZA==</p>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[],"owner":"48907826","collectionId":"cff87b0a-f239-4ae5-b249-3a4236af4508","publishedId":"2sBXwnsXYK","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-06-12T13:55:07.000Z"},"item":[{"name":"Casino Aggregator API","item":[{"name":"Aggregator API","item":[{"name":"Games API","item":[{"name":"Get Game Link","id":"2c46b2d1-44c5-4a22-9649-b72bd7f627a3","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link","description":"<p>Returns the Landing URL of the chosen game. Casino has to forward User to returned URL. There are several ways to forward the User:</p>\n<ol>\n<li><p>Embed URL into iframe on your site;</p>\n</li>\n<li><p>Redirect User to URL;</p>\n</li>\n<li><p>Open URL in new window/tab of browser.</p>\n</li>\n</ol>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>gameId</code>(string, required) - Id from get games request</p>\n</li>\n<li><p><code>urls</code> (object, required)</p>\n<ul>\n<li><p><code>returnUrl</code> (string, required) - Url to provider page on casino</p>\n</li>\n<li><p><code>depositUrl</code> (string required) - Url to deposit page on casino</p>\n</li>\n</ul>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>externalId</code> (string, required) - User id in casino system. Must be unique</p>\n</li>\n<li><p><code>username</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, optional)</p>\n</li>\n<li><p><code>surname</code> (string, optional)</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Values: 'Mr', 'Mrs', 'Ms', 'Miss'</p>\n</li>\n<li><p><code>ip</code> (string, required)</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n<li><p><code>device</code> (object, required)</p>\n<ul>\n<li><p><code>operatingSystem</code> (enum, required) - Values 'WINDOWS', 'LINUX', 'MACOS', 'IOS', 'ANDROID'</p>\n</li>\n<li><p><code>platform</code> (enum, required) - Values 'BROWSER', 'NATIVE'</p>\n</li>\n</ul>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n</li>\n<li><p><code>session</code> (object, optional)</p>\n<ul>\n<li><code>externalId</code> (string, required) - Session Id in casino system. Will be attached to callbacks in Casino API, see session object</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>link</code>(string, required) - Link to open game</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","games","link"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"c177820f-e31a-4f54-a179-73631166568e","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"link\": \"https://example.com\"\n}"},{"id":"e70d4d33-5438-49a0-88ab-b2927dac7fe1","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 104,\n    \"errorMessage\": \"Game not found\"\n}"}],"_postman_id":"2c46b2d1-44c5-4a22-9649-b72bd7f627a3"},{"name":"Get Demo Game Link","id":"2824eb24-4c0b-441b-9c76-bcc36e1bc903","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link/demo","description":"<p>Returns the Landing URL of the chosen game in Demo mode.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>gameId</code>(string, required) - Id from get games request</p>\n</li>\n<li><p><code>urls</code> (object, required)</p>\n<ul>\n<li><p><code>returnUrl</code> (string, required) - Url to provider page on casino</p>\n</li>\n<li><p><code>depositUrl</code> (string required) - Url to deposit page on casino</p>\n</li>\n</ul>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>ip</code> (string, required)</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n<li><p><code>device</code> (object, required)</p>\n<ul>\n<li><p><code>operatingSystem</code> (enum, required) - Values 'WINDOWS', 'LINUX', 'MACOS', 'IOS', 'ANDROID'</p>\n</li>\n<li><p><code>platform</code> (enum, required) - Values 'BROWSER', 'NATIVE'</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>link</code>(string, required) - Link to open game</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","games","link","demo"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"34821f4e-34ae-4ddf-a93e-f29e961c6fd7","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link/demo"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"link\": \"https://example.com\"\n}"},{"id":"906b2d0d-af2b-4d42-abb7-e021edca80d4","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/link/demo"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 104,\n    \"errorMessage\": \"Game not found\"\n}"}],"_postman_id":"2824eb24-4c0b-441b-9c76-bcc36e1bc903"},{"name":"Get Games","id":"bcdb8b7e-0b59-4daf-bb7b-6231e51eefff","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games","description":"<p>Returns the list of games available for brand</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>provider</code> (string, optional) - Provider which games should be returned. If not present all games will be returned</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>List of Objects:</p>\n<ul>\n<li><p><code>id</code> (string, required) - Id of the game. Unique among all games</p>\n</li>\n<li><p><code>providerGameId</code> (string, required) - Id of the game in provider system.</p>\n</li>\n<li><p><code>name</code> (string, required)</p>\n</li>\n<li><p><code>isActive</code> (boolean, required)</p>\n</li>\n<li><p><code>isDemoAvailable</code> (boolean, required)</p>\n</li>\n<li><p><code>isFreeBonusBuyAvailable</code> (boolean, required) - if this game is applicable for free bonus buys</p>\n</li>\n<li><p><code>previewImages</code> (list of objects, required)</p>\n<ul>\n<li><p><code>size</code> (enum, required) - Values: 'S', 'M', 'L'</p>\n</li>\n<li><p><code>url</code> (string, required) - Url to game's preview image</p>\n</li>\n</ul>\n</li>\n<li><p><code>backgroundImageUrl</code> (string, optional) - Url to game's background image</p>\n</li>\n<li><p><code>provider</code> (string, required) - Provider name</p>\n</li>\n<li><p><code>product</code> (enum, required) - Values: 'LIVE_CASINO', 'CASINO', 'GAMES', 'VIRTUAL'</p>\n</li>\n<li><p><code>createdAt</code> (long, required) - Created at timestamp</p>\n</li>\n<li><p><code>devices</code> (list of enums, required) - Values: 'DESKTOP', 'MOBILE'</p>\n</li>\n<li><p><code>gameTags</code> (list of objects, required)</p>\n<ul>\n<li><p><code>id</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, required)</p>\n</li>\n</ul>\n</li>\n<li><p><code>betValues</code> (list of objects, required) - Bet values to create free spins</p>\n<ul>\n<li><p><code>currency</code> (string, required) - Bet value currency</p>\n</li>\n<li><p><code>values</code> (list of long, required) - Possible free spins bets values. Values are in Money format</p>\n</li>\n</ul>\n</li>\n<li><p><code>rtp</code> (object, optional) - Game RTP value</p>\n<ul>\n<li><p><code>type</code> (string, required) - RTP object type (Fixed)</p>\n</li>\n<li><p><code>value</code> (double, required) - RTP value</p>\n</li>\n</ul>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","games"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"9922215b-4bac-425c-a2c5-a7fed5c78b26","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n    {\n        \"id\": \"dd4c01ce-1230-41a3-a5af-24bb867db622\",\n        \"providerGameId\": \"test-game\",\n        \"name\": \"Test Game\",\n        \"isActive\": true,\n        \"isDemoAvailable\": true,\n        \"isFreeBonusBuyAvailable\": true,\n        \"previewImages\": [\n            {\n                \"size\": \"S\",\n                \"url\": \"https://example.com\"\n            },\n            {\n                \"size\": \"M\",\n                \"url\": \"https://example.com\"\n            },\n            {\n                \"size\": \"L\",\n                \"url\": \"https://example.com\"\n            }\n        ],\n        \"backgroundImageUrl\": null,\n        \"provider\": \"provider\",\n        \"product\": \"CASINO\",\n        \"createdAt\": 1685879114717,\n        \"devices\": [\n            \"DESKTOP\",\n            \"MOBILE\"\n        ],\n        \"gameTags\": [\n            {\n                \"id\": \"08d657d2-9678-4d3f-9431-152a6db60e1f\",\n                \"name\": \"Slots\"\n            }\n        ],\n        \"betValues\": [\n            {\n                \"currency\": \"EUR\",\n                \"values\": [\n                    25,\n                    50,\n                    75,\n                    100\n                ]\n            },\n            {\n                \"currency\": \"USD\",\n                \"values\": [\n                    25,\n                    50,\n                    75,\n                    100\n                ]\n            }\n        ]\n    }\n]"},{"id":"9d8beaa5-c819-4b21-826f-4ad668ce0198","name":"success with provider","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"provider\": \"provider2\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[]"},{"id":"a64a8b80-90fb-4eff-bc3a-1ce87a812aab","name":"success with provider null","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"provider\": null\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n    {\n        \"id\": \"dd4c01ce-1230-41a3-a5af-24bb867db622\",\n        \"providerGameId\": \"test-game\",\n        \"name\": \"Test Game\",\n        \"isActive\": true,\n        \"isDemoAvailable\": true,\n        \"isFreeBonusBuyAvailable\": true,\n        \"previewImages\": [\n            {\n                \"size\": \"S\",\n                \"url\": \"https://example.com\"\n            },\n            {\n                \"size\": \"M\",\n                \"url\": \"https://example.com\"\n            },\n            {\n                \"size\": \"L\",\n                \"url\": \"https://example.com\"\n            }\n        ],\n        \"backgroundImageUrl\": null,\n        \"provider\": \"provider\",\n        \"product\": \"CASINO\",\n        \"createdAt\": 1685879114717,\n        \"devices\": [\n            \"DESKTOP\",\n            \"MOBILE\"\n        ],\n        \"gameTags\": [\n            {\n                \"id\": \"08d657d2-9678-4d3f-9431-152a6db60e1f\",\n                \"name\": \"Slots\"\n            }\n        ],\n        \"betValues\": [\n            {\n                \"currency\": \"EUR\",\n                \"values\": [\n                    25,\n                    50,\n                    75,\n                    100\n                ]\n            },\n            {\n                \"currency\": \"USD\",\n                \"values\": [\n                    25,\n                    50,\n                    75,\n                    100\n                ]\n            }\n        ]\n    }\n]"},{"id":"54e21638-bde3-4883-94d1-c06c6135fe0a","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games"},"status":"Internal Server Error","code":500,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Internal Server Error\"\n}"},{"id":"da8e69ea-8349-4fcc-b4dd-dd6b4294b508","name":"fail Provider not found","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"provider\": \"provider99\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games"},"status":"Internal Server Error","code":500,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 117,\n    \"errorMessage\": \"Provider not found\"\n}"}],"_postman_id":"bcdb8b7e-0b59-4daf-bb7b-6231e51eefff"},{"name":"Get Providers","id":"292b464e-d98a-4de0-a195-2f87c67b9a4e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/providers","description":"<p>Returns details about game providers.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>brandId</code> (int, required) - Brand id provided by aggregator provider</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>List of Objects:</p>\n<ul>\n<li><p><code>name</code> (string, required) - Provider name</p>\n</li>\n<li><p><code>roundHistory</code> (boolean, required)</p>\n</li>\n<li><p><code>products</code> (list of enum, required) - Values: 'VIRTUAL', 'GAMES', 'LIVE_CASINO', 'CASINO', 'SPORTS', 'POKER'</p>\n</li>\n<li><p><code>bonuses</code> (list of enum, required) - Values: 'FREE_SPINS'</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","providers"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"5fdee0f9-f32f-4a5c-a1dc-af99c724d339","name":"success","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json","type":"text"},{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/providers"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n    {\n        \"name\": \"provider\",\n        \"roundHistory\": true,\n        \"products\": [\n            \"CASINO\",\n            \"GAMES\",\n            \"LIVE_CASINO\"\n        ],\n        \"bonuses\": []\n    },\n    {\n        \"name\": \"provider2\",\n        \"roundHistory\": false,\n        \"products\": [\n            \"CASINO\",\n            \"VIRTUAL\"\n        ],\n        \"bonuses\": [\n            \"FREE_SPINS\"\n        ]\n    },\n    {\n        \"name\": \"provider3\",\n        \"roundHistory\": false,\n        \"products\": [\n            \"CASINO\",\n            \"GAMES\",\n            \"SPORTS\"\n        ],\n        \"bonuses\": []\n    },\n    {\n        \"name\": \"provider4\",\n        \"roundHistory\": false,\n        \"products\": [\n            \"SPORTS\"\n        ],\n        \"bonuses\": []\n    }\n]"},{"id":"9276de09-dd86-4ede-b708-7d3c94981d02","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/providers"},"status":"Internal Server Error","code":500,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Internal Server Error\"\n}"}],"_postman_id":"292b464e-d98a-4de0-a195-2f87c67b9a4e"},{"name":"Get Jackpot Feed","id":"3915581a-e496-49ec-9953-b3e8bda67796","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"providers\":[\"some-provider\"],\n    \"currency\": \"EUR\",\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/feeds/jackpot","description":"<p>Retursn jackpot feed. Process of fetching jackpot data is asynchronious and it's expected to use some sort of polling mechanism to get latest jackpot details.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>providers</code> (string array, required) - Ids of providers to fetch jackpots</p>\n</li>\n<li><p><code>currency</code> (enum, required) - Currency of jackpot</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Response body is a dedicated jackpot pool</p>\n<p>List of Objects:</p>\n<ul>\n<li><p><code>provider</code> (string, required) - Provider name</p>\n</li>\n<li><p><code>name</code> (string, optional) - Name of a jackpot given by provider</p>\n</li>\n<li><p><code>gameIds</code> (string array, optional) - Game ids applicable for jackpot</p>\n</li>\n<li><p><code>tiers</code> (object array, required) - Tiers for that pool</p>\n<ul>\n<li><p><code>level</code> (int, required) - Jackpot level</p>\n</li>\n<li><p><code>amount</code> (long, required) - Jackpot amount</p>\n</li>\n<li><p><code>currency</code> (enum, required) - Jackpot amount currency</p>\n</li>\n<li><p><code>winnersCount</code> (int, optional) - Jackpot Tier winner count given by provider</p>\n</li>\n</ul>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","games","feeds","jackpot"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"286ac38d-2e7a-48c9-9f02-deb47e75e97e","name":"success","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json","type":"text"},{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"providers\":[\"some-provider\"],\n    \"currency\": \"EUR\",\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/feeds/jackpot"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n  {\n    \"provider\": \"some-provider\",\n    \"tiers\": [\n      {\n        \"level\": 0,\n        \"amount\": 541519,\n        \"currency\": \"USD\"\n      },\n      {\n        \"level\": 1,\n        \"amount\": 2362556,\n        \"currency\": \"USD\"\n      },\n      {\n        \"level\": 2,\n        \"amount\": 1330052,\n        \"currency\": \"USD\"\n      }\n    ]\n  }\n]"},{"id":"cd53a51f-a94b-4588-8d48-5093b8969e03","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"providers\":[\"some-provider\"],\n    \"currency\": \"EUR\",\n    \"brandId\": 0\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/games/feeds/jackpot"},"status":"Internal Server Error","code":500,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Internal Server Error\"\n}"}],"_postman_id":"3915581a-e496-49ec-9953-b3e8bda67796"}],"id":"23b1bc3d-c1e8-45a4-ac7e-91568ed26d72","description":"<p>Provides methods to display and launch games on a Casino.</p>\n","event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"42d3e40b-e97b-44f4-890c-a81533946245"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"3f6b26c2-0e78-45da-9b52-b8c2b76cc06c"}}],"_postman_id":"23b1bc3d-c1e8-45a4-ac7e-91568ed26d72","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}},{"name":"Free Spins API","item":[{"name":"Get Player Active Free Spins","id":"36f6146b-3ba0-4eab-9619-151bf8562445","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins","description":"<p>Returns currently active player Free Spins.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>List of Objects:</p>\n<ul>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>gameIds</code> (string array, required) - Ids from get games request</p>\n</li>\n<li><p><code>betValue</code> (object, required) - Bet value from games request</p>\n<ul>\n<li><p><code>currency</code> (string, required) - Bet value currency</p>\n</li>\n<li><p><code>value</code> (long, required) - Bet value from games request. In Money format</p>\n</li>\n</ul>\n</li>\n<li><p><code>amount</code> (integer, required) - Amount of free spins</p>\n</li>\n<li><p><code>currentAmount</code> (integer, required) - Amount of used free spins</p>\n</li>\n<li><p><code>startDate</code> (long, required) - Free Spins start date timestamp</p>\n</li>\n<li><p><code>endDate</code> (long, required) - Free Spins end date timestamp</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","free-spins"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"b7d2f6df-289a-4472-9179-dcbedb24eb74","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n  {\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"gameIds\": [\"dd4c01ce-1230-41a3-a5af-24bb867db622\"],\n    \"betValue\": {\n      \"currency\": \"TRY\",\n      \"value\": 100\n    },\n    \"amount\": 10,\n    \"currentAmount\": 0,\n    \"startDate\": 1727695739999,\n    \"endDate\": 1727696280002\n  }\n]"},{"id":"86709465-0cc0-4d24-8af1-a289592e0f39","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"invalidExternalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 109,\n  \"errorMessage\": \"Invalid User\"\n}"}],"_postman_id":"36f6146b-3ba0-4eab-9619-151bf8562445"},{"name":"Create Player Free Spins","id":"bf73a05d-c5e5-4a70-a775-3c3f9b4b8e2f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameId\": \"dd4c01ce-1230-41a3-a5af-24bb867db622\",\n    \"amount\": 10,\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create","description":"<p>Endpoint for creating Free Spins</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>externalId</code> (string, required) - User id in casino system. Must be unique</p>\n</li>\n<li><p><code>username</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, optional)</p>\n</li>\n<li><p><code>surname</code> (string, optional)</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Values: 'Mr', 'Mrs', 'Ms', 'Miss'</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n</ul>\n</li>\n<li><p><code>gameId</code> (string, required) - Id from get games request</p>\n</li>\n<li><p><code>amount</code> (integer, required) - Amount of free spins</p>\n</li>\n<li><p><code>betValue</code> (object, required) - Bet value from games request</p>\n<ul>\n<li><p><code>currency</code> (string, required) - Bet value code currency</p>\n</li>\n<li><p><code>value</code> (long, required) - Bet value from games request. In Money format</p>\n</li>\n</ul>\n</li>\n<li><p><code>startDate</code> (long, required) - Free Spins start date timestamp</p>\n</li>\n<li><p><code>endDate</code> (long, required) - Free Spins end date timestamp</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>gameId</code> (string, optional) - Id from get games request</p>\n</li>\n<li><p><code>gameIds</code> (string array, optional) - Ids from get games request, either gameId or gameIds should be present. If both provided behaviour is undefined</p>\n</li>\n<li><p><code>betValue</code> (object, required) - Bet value from games request</p>\n<ul>\n<li><p><code>currency</code> (string, required) - Bet value code currency</p>\n</li>\n<li><p><code>value</code> (long, required) - Bet value from games request. In Money format</p>\n</li>\n</ul>\n</li>\n<li><p><code>startDate</code> (long, required) - Free Spins start date timestamp</p>\n</li>\n<li><p><code>endDate</code> (long, required) - Free Spins end date timestamp</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","free-spins","create"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"83b52e75-0f41-4bab-b004-666b3c461523","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameId\": \"dd4c01ce-1230-41a3-a5af-24bb867db622\",\n    \"gameIds\": [\"dd4c01ce-1230-41a3-a5af-24bb867db622\"],\n    \"amount\": 10,\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\"\n}"},{"id":"e8a44b4e-5254-4f49-8335-560b824f37a9","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameId\": \"7dc23ad9-ec37-47d2-a94b-b608687c940b\",\n    \"gameIds\": [\"dd4c01ce-1230-41a3-a5af-24bb867db622\"],\n    \"amount\": 10,\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 114,\n  \"errorMessage\": \"Free Spins not supported by provider\"\n}"}],"_postman_id":"bf73a05d-c5e5-4a70-a775-3c3f9b4b8e2f"},{"name":"Create Player Free Bonus Buy","id":"37c5ee21-0c29-4e14-a053-c59b8cb84a71","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameIds\": [\n        \"dd4c01ce-1230-41a3-a5af-24bb867db622\"\n    ],\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create-bonus-buy","description":"<p>Endpoint for creating Free Spins</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>externalId</code> (string, required) - User id in casino system. Must be unique</p>\n</li>\n<li><p><code>username</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, optional)</p>\n</li>\n<li><p><code>surname</code> (string, optional)</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Values: 'Mr', 'Mrs', 'Ms', 'Miss'</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n</ul>\n</li>\n<li><p><code>gameIds</code> (string array, required) - Ids from get games request</p>\n</li>\n<li><p><code>betValue</code> (object, required) - Bet value from games request</p>\n<ul>\n<li><p><code>currency</code> (string, required) - Bet value code currency</p>\n</li>\n<li><p><code>value</code> (long, required) - Bet value from games request. In Money format</p>\n</li>\n</ul>\n</li>\n<li><p><code>startDate</code> (long, required) - Free Spins start date timestamp</p>\n</li>\n<li><p><code>endDate</code> (long, required) - Free Spins end date timestamp</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","free-spins","create-bonus-buy"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"29417a07-b815-4df2-a8ff-b4da4e8f695c","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameIds\": [\"dd4c01ce-1230-41a3-a5af-24bb867db622\"],\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\"\n}"},{"id":"8ebcf78f-bf95-430c-8a3a-209ce6d5b086","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"currency\": \"TRY\",\n        \"locale\": \"tr_TR\"\n    },\n    \"gameIds\": [\"dd4c01ce-1230-41a3-a5af-24bb867db622\"],\n    \"betValue\": {\n        \"currency\": \"TRY\",\n        \"value\": 100\n    },\n    \"startDate\": 1727698989326,\n    \"endDate\": 1727699569328\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 114,\n  \"errorMessage\": \"Free Spins not supported by provider\"\n}"}],"_postman_id":"37c5ee21-0c29-4e14-a053-c59b8cb84a71"},{"name":"Cancel Player Free Spins","id":"74f00518-e29b-4204-a6f0-490c0ddc9095","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"externalUserId\": \"externalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/cancel","description":"<p>Endpoint for cancelling Free Spins</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Id of Free Spins in casino system</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","free-spins","cancel"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"4995f52b-6ec7-432e-bb9f-406df81f964b","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"externalUserId\": \"externalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/cancel"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\"\n}"},{"id":"02293125-dbc2-4196-8784-5bc7bca92936","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalFreeSpinsId\": \"62922980-23bb-7361-a652-7c50f9cf62ce\",\n    \"externalUserId\": \"invalidExternalId\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/free-spins/cancel"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 109,\n  \"errorMessage\": \"Invalid User\"\n}"}],"_postman_id":"74f00518-e29b-4204-a6f0-490c0ddc9095"}],"id":"508dfbec-90be-4a3c-b712-95935bee278c","description":"<p>Provides methods to manage rewards (freespins, freebets, prizes).</p>\n","event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"9170c482-9e2b-475d-88f5-32b654cc2908"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"ad35bcc4-40f4-4f01-91e0-a036b51ef943"}}],"_postman_id":"508dfbec-90be-4a3c-b712-95935bee278c","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}},{"name":"Lobby API","item":[{"name":"Get Lobby Link","id":"0244a303-61e7-4e56-bb84-f65f1a935f5c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link","description":"<p>Returns the Landing URL of the Lobby.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>urls</code> (object, required)</p>\n<ul>\n<li><p><code>returnUrl</code> (string, required) - Url to provider page on casino</p>\n</li>\n<li><p><code>depositUrl</code> (string, required) - Url to deposit page on casino</p>\n</li>\n</ul>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>externalId</code> (string, required) - User id in casino system. Must be unique</p>\n</li>\n<li><p><code>username</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, optional)</p>\n</li>\n<li><p><code>surname</code> (string, optional)</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Values: 'Mr', 'Mrs', 'Ms', 'Miss'</p>\n</li>\n<li><p><code>ip</code> (string, required)</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n<li><p><code>device</code> (object, required)</p>\n<ul>\n<li><p><code>operatingSystem</code> (enum, required) - Values 'WINDOWS', 'LINUX', 'MACOS', 'IOS', 'ANDROID'</p>\n</li>\n<li><p><code>platform</code> (enum, required) - Values 'BROWSER', 'NATIVE'</p>\n</li>\n</ul>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n</li>\n<li><p><code>session</code> (object, optional)</p>\n<ul>\n<li><code>externalId</code> (string, required) - Session Id in casino system. Will be attached to callbacks in Casino API, see session object</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>link</code>(string, required) - Link to open lobby</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","lobby","link"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"aafc918f-7849-44e6-b98c-9bc362a89059","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"link\": \"https://example.com\"\n}"},{"id":"27a35f49-5c47-4516-99db-a24f7a64680d","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"user\": {\n        \"externalId\": \"externalId\",\n        \"username\": \"test\",\n        \"name\": \"test\",\n        \"surname\": \"test\",\n        \"honorific\": \"Mr\",\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        },\n        \"currency\": \"TRY\"\n    },\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 4,\n  \"errorMessage\": \"Deserialization error\"\n}"}],"_postman_id":"0244a303-61e7-4e56-bb84-f65f1a935f5c"},{"name":"Get Demo Lobby Link","id":"dc0f3286-980a-4516-9e65-0fb7c22217a6","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link/demo","description":"<p>Returns the Landing URL of the Demo Lobby.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>urls</code> (object, required)</p>\n<ul>\n<li><p><code>returnUrl</code> (string, required) - Url to provider page on casino</p>\n</li>\n<li><p><code>depositUrl</code> (string, required) - Url to deposit page on casino</p>\n</li>\n</ul>\n</li>\n<li><p><code>user</code> (object, required)</p>\n<ul>\n<li><p><code>ip</code> (string, required)</p>\n</li>\n<li><p><code>locale</code> (string, required)</p>\n</li>\n<li><p><code>device</code> (object, required)</p>\n<ul>\n<li><p><code>operatingSystem</code> (enum, required) - Values 'WINDOWS', 'LINUX', 'MACOS', 'IOS', 'ANDROID'</p>\n</li>\n<li><p><code>platform</code> (enum, required) - Values 'BROWSER', 'NATIVE'</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>link</code>(string, required) - Link to open lobby</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","lobby","link","demo"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"4c07f5e9-6b38-4dc7-b219-b04b4941df54","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"urls\": {\n        \"returnUrl\": \"https://example.com\",\n        \"depositUrl\": \"https://example.com\"\n    },\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link/demo"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"link\": \"https://example.com\"\n}"},{"id":"c7ae6885-4a13-4a8b-962b-bd3a75d0ca6a","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"user\": {\n        \"ip\": \"0.0.0.0\",\n        \"locale\": \"tr_TR\",\n        \"device\": {\n            \"operatingSystem\": \"LINUX\",\n            \"platform\": \"BROWSER\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/lobby/link/demo"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 4,\n  \"errorMessage\": \"Deserialization error\"\n}"}],"_postman_id":"dc0f3286-980a-4516-9e65-0fb7c22217a6"}],"id":"9264259b-7b40-4169-8bd1-4fb87aded43a","description":"<p>Provides methods to show Games Lobby.</p>\n<p>Games Lobby contains all games availbale to brand and ready to play</p>\n","event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"7e730260-6efb-497e-9ec6-04bab9b97353"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"97e68375-1d4a-4900-a831-a5ceafeb7ca5"}}],"_postman_id":"9264259b-7b40-4169-8bd1-4fb87aded43a","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}},{"name":"Round API","item":[{"name":"Get Private Round History","id":"01b75b86-d3c5-4611-9bc5-ff41624af71e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/history","description":"<p>Returns the URL of a game round detail. Designed for Backoffice usage, because there might be sensitive data here.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider i</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>roundId</code> (string, required) - Id of the round</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>value</code> (string, required) - URL that contains round info in provider system, it's preferred to insert it into iframe.src attribut</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","round","private","history"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"05c8e363-d2fc-44ba-be70-a65017234592","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/history"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"value\": \"https://example.com\"\n}"},{"id":"a368797f-7ac9-457f-93ab-3141a389ce6e","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/history"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 115,\n  \"errorMessage\": \"Round not found\"\n}"}],"_postman_id":"01b75b86-d3c5-4611-9bc5-ff41624af71e"},{"name":"Get Private Round Replay","id":"59a8e2bb-b607-488a-9d01-c69ec3f162b5","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/replay","description":"<p>Returns the URL of a game round replay. This API should be only used to retrive replays for rounds with big multipliers.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider i</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>roundId</code> (string, required) - Id of the round</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>value</code> (string, required) - URL that contains round replay in provider system, it's preferred to insert it into iframe.src attribut</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","round","private","replay"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"461be172-331b-43c9-923d-cdee006cb27e","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/replay"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"value\": \"https://example.com\"\n}"},{"id":"fea93e6d-73a5-45b1-bfe0-445acd63cb37","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/private/replay"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 115,\n  \"errorMessage\": \"Round not found\"\n}"}],"_postman_id":"59a8e2bb-b607-488a-9d01-c69ec3f162b5"},{"name":"Get Public Round History","id":"4e319ac5-8d5b-4170-b975-bd98945db4bc","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/public/history","description":"<p>Returns the URL of a game round detail. Designed for Public usage, i.e. you can use this API to display link on your Player UI.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider i</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>roundId</code> (string, required) - Id of the round</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>value</code> (string, required) - URL that contains round info in provider system, it's preferred to insert it into iframe.src attribut</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","round","public","history"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"6448c437-c74c-44d9-870e-2be152c8c7cc","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/public/history"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"value\": \"https://example.com\"\n}"},{"id":"66c787f4-e01f-49e5-a134-a5da13a81ba2","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/public/history"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 115,\n  \"errorMessage\": \"Round not found\"\n}"}],"_postman_id":"4e319ac5-8d5b-4170-b975-bd98945db4bc"},{"name":"Game Pending Round Feed","id":"965b91c9-4d0c-46fa-9d8a-9e2d662496fe","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/feeds/game/pending","description":"<p>This report returns all the game rounds that were started by a certain player but not completed yet.<br />Customer is expected to use this API</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider i</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>providers</code> (string array, optional) - Provider value received from providers endpoint, if no given - all prvoiders will be used</p>\n</li>\n<li><p><code>products</code> (enum array, optional) - Values: 'LIVE_CASINO', 'CASINO', 'GAMES', 'VIRTUAL', if empty will search for all products</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Array of objects:</p>\n<ul>\n<li><p><code>id</code> (string, required) - ID of pending round</p>\n</li>\n<li><p><code>gameId</code> (string, required) - game identifier</p>\n</li>\n<li><p><code>betAmount</code> (number, required) - pending bet amount</p>\n</li>\n<li><p><code>currency</code> (enum, required) - round currency</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","round","feeds","game","pending"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"0b1a8891-a86d-47df-89a7-ae3fb06ae08f","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"products\": [\"LIVE_CASINO\"]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/feeds/game/pending"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"[\n    {\n        \"id\": \"round-id\",\n        \"gameId\":\"game-id\",\n        \"betAmount\": 100,\n        \"currency\": \"EUR\"\n    }\n]"},{"id":"77fbc69b-6d9a-44f0-ba58-fad89b35e6f5","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"externalId\",\n    \"products\": [\"LIVE_CASINO\"]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/round/feeds/game/pending"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 115,\n  \"errorMessage\": \"Round not found\"\n}"}],"_postman_id":"965b91c9-4d0c-46fa-9d8a-9e2d662496fe"}],"id":"35705b54-6455-49bb-a4f8-5a2123460d55","_postman_id":"35705b54-6455-49bb-a4f8-5a2123460d55","description":"","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}}],"id":"ee254cf7-0b95-41f2-b462-69dcfc4514a9","description":"<p>Requests sent from Casino to Aggregator Provider</p>\n","event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"50f7b66c-2005-4e9b-b715-2cce5fe50329"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"5a5ddc99-ae68-4df8-9ade-b3425cdb5f81"}}],"_postman_id":"ee254cf7-0b95-41f2-b462-69dcfc4514a9","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}},{"name":"Casino API","item":[{"name":"Get Balance","id":"77773b9d-6a91-4ff8-b55f-baf50ba574db","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"currency\": \"TRY\",\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/get-balance","description":"<p>Called when player's balance is needed. Casino is expected to return player's current balance</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n<li><p><code>provider</code> (string, optional) - Provider which requests the balance. This value might not be available in certain situations</p>\n</li>\n<li><p><code>session</code> (object, optional)</p>\n<ul>\n<li><code>externalId</code> (string, required) - Session Id in casino system received on game launch</li>\n</ul>\n</li>\n<li><p><code>gameId</code>(string, optional) - Game Id</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\"><strong>Response Body Description:</strong></h4>\n<p>Object:</p>\n<ul>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>balance</code> (long, required) - In Money format</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["get-balance"],"host":["{callbackUrl}"],"query":[],"variable":[]}},"response":[{"id":"af9bede3-82ec-4209-a3bd-216447d769c5","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"currency\": \"TRY\",\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    },\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/get-balance"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"externalUserId\": \"externalId\",\n    \"balance\": 100000,\n    \"currency\": \"TRY\"\n}"},{"id":"57b88bfb-0a14-4e34-8e47-1b855baea2c5","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e2ludmFsaWRfdXNlcm5hbWV9OntwYXNzd29yZH0=","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"currency\": \"TRY\",\n    \"provider\": \"some-provider\",\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    },\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/get-balance"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\" : 2,\n    \"errorMessage\" : \"Invalid credentials\"\n}"}],"_postman_id":"77773b9d-6a91-4ff8-b55f-baf50ba574db"},{"name":"Transaction","id":"e0372ad2-57fb-4067-b901-6417f894914f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"WIN\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isRoundFinished\": true,\n    \"amount\": 200,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": null,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction","description":"<p>Endpoint used for various transactions:</p>\n<ul>\n<li><p><strong>BET</strong> - Called when the User places a bet.</p>\n</li>\n<li><p><strong>WIN</strong> - Called when the User wins.</p>\n</li>\n<li><p><strong>ROLLBACK</strong> - Called when there is need to roll back the effect of the referenced transaction.</p>\n</li>\n<li><p><strong>FREE_SPINS_BET</strong> - Called when the User places a Free Spins bet.</p>\n</li>\n<li><p><strong>FREE_SPINS_WIN</strong> - Called when the User wins in Free Spins round.</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>txType</code> (enum, required) - Values: 'BET', 'WIN', 'ROLLBACK', 'FREE_SPINS_BET', 'FREE_SPINS_WIN'</p>\n</li>\n<li><p><code>txId</code> (string, required) - Id of the transaction. Unique among all txs</p>\n</li>\n<li><p><code>roundId</code> (string, required) - Id of the round in aggregator system</p>\n</li>\n<li><p><code>providerRoundId</code> (string, required) - Id of the round in provider system</p>\n</li>\n<li><p><code>isForced</code> (boolean, required) - BET should be accepted even if player doesn't have enough money on balance (balance can go negative)</p>\n</li>\n<li><p><code>isJackpot</code> (boolean, required) - Indicates if current transaction is related to jackpot</p>\n</li>\n<li><p><code>isBonusBuy</code> (boolean, required) - Indicates if current transaction is related to bonus buy</p>\n</li>\n<li><p><code>isRoundFinished</code> (boolean, required)</p>\n</li>\n<li><p><code>isPromotion</code> (boolean, required) - Transaction is related to a promotion bet / win</p>\n</li>\n<li><p><code>amount</code> (long, required) - Transaction amount. In Money format</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n<li><p><code>provider</code> (string, required) - Provider name</p>\n</li>\n<li><p><code>rolledBackTxId</code> (string, optional) - Not null in case of rollback. Tx id to rollback</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, optional) - Not null in case of free spins transaction</p>\n</li>\n<li><p><code>gameId</code> (string, optional) - Id from get games request. Can be null in case of jackpots, tips etc</p>\n</li>\n<li><p><code>timestamp</code> (long, required) - Transaction process timestamp in aggregator provider system</p>\n</li>\n<li><p><code>session</code> (object, optional)</p>\n<ul>\n<li><code>externalId</code> (string, required) - Session Id in casino system received on game launch</li>\n</ul>\n</li>\n<li><p><code>details</code> (object, optional) - Sportsbook bet context. Populated only for sportsbook transactions; null for casino game transactions. See \"Sportsbook Scheme\" folder for the schema.</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>txId</code> (string, required) - Transaction id in casino system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>balance</code> (long, required) - Balance after transaction. In Money format</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["transaction"],"host":["{callbackUrl}"],"query":[],"variable":[]}},"response":[{"id":"5e3fd44b-549e-4331-b239-9220e0c8f6cc","name":"bet","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"BET\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": false,\n    \"amount\": 200,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": null,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"txId\": \"845676317\",\n    \"externalUserId\": \"externalId\",\n    \"balance\": \"133937020\",\n    \"currency\": \"TRY\"\n}"},{"id":"fa8be0e5-37f3-439e-98dc-efd7487db139","name":"fail - bet","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"BET\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": false,\n    \"amount\": 20000,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": null,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\" : 106,\n    \"errorMessage\" : \"Not enough funds\"\n}"},{"id":"10d90634-4ceb-4970-a86c-a4761c03123a","name":"free spins bet","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"FREE_SPINS_BET\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": false,\n    \"amount\": 0,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": \"05699a64-e4a0-4091-86cd-b5e9d3823f67\",\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"txId\": \"123676317\",\n    \"externalUserId\": \"externalId\",\n    \"balance\": \"133937020\",\n    \"currency\": \"TRY\"\n}"},{"id":"8fa2835a-9419-4079-b0ab-42abb6c65ad3","name":"rollback","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"ROLLBACK\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": true,\n    \"amount\": 200,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": \"0192f780-33d8-7481-a8ae-d331c9ba50e2\",\n    \"externalFreeSpinsId\": null,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"txId\": \"735676317\",\n    \"externalUserId\": \"externalId\",\n    \"balance\": \"133938120\",\n    \"currency\": \"TRY\"\n}"},{"id":"9744371a-2fb9-4634-9a5c-53cd04c994a5","name":"win","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"WIN\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": true,\n    \"amount\": 200,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": null,\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"txId\" : \"145676328\",\n    \"externalUserId\" : \"externalId\",\n    \"balance\" : \"133938020\",\n    \"currency\" : \"TRY\"\n  }"},{"id":"66d32ef9-43c7-4f8f-8020-478e3bb0e2ec","name":"free spins win","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"txType\": \"FREE_SPINS_WIN\",\n    \"txId\": \"af7d269d-c6c7-472a-a4c7-b73b9d78ab24\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isForced\": false,\n    \"isRoundFinished\": true,\n    \"amount\": 200,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"rolledBackTxId\": null,\n    \"externalFreeSpinsId\": \"05699a64-e4a0-4091-86cd-b5e9d3823f67\",\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"isJackpot\": false,\n    \"isBonusBuy\": true,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/transaction"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"txId\" : \"441676328\",\n    \"externalUserId\" : \"externalId\",\n    \"balance\" : \"133938020\",\n    \"currency\" : \"TRY\"\n  }"}],"_postman_id":"e0372ad2-57fb-4067-b901-6417f894914f"},{"name":"End Round","id":"cbefb9a0-e5d4-4323-9cfa-8ebcf833370b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isRoundFinished\": true,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round","description":"<p>Called to notify about round end.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>roundId</code> (string, required) - Id of the round</p>\n</li>\n<li><p><code>providerRoundId</code> (string, required) - Id of the round in provider system</p>\n</li>\n<li><p><code>isRoundFinished</code> (boolean, required)</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n<li><p><code>provider</code> (string, required) - Provider name</p>\n</li>\n<li><p><code>gameId</code> (string, optional) - Id from get games request. Can be null in case of jackpots, tips etc</p>\n</li>\n<li><p><code>timestamp</code> (long, required) - End round timestamp in aggregator provider system</p>\n</li>\n<li><p><code>session</code> (object, optional)</p>\n<ul>\n<li><code>externalId</code> (string, required) - Session Id in casino system received on game launch</li>\n</ul>\n</li>\n<li><p><code>details</code> (object, optional) - Sportsbook bet context. Populated only for sportsbook transactions; null for casino game transactions. See \"Sportsbook Scheme\" folder for the schema.</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>balance</code> (long, required) - Balance in Money format</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["end-round"],"host":["{callbackUrl}"],"query":[],"variable":[]}},"response":[{"id":"c87049bc-028b-4a1f-9bdc-7fd8ab4ceceb","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isRoundFinished\": true,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"externalUserId\": \"externalId\",\n  \"balance\": 100000,\n  \"currency\": \"TRY\"\n}"},{"id":"672fb0b2-9481-4c45-91f3-ab8ed44563bb","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e2ludmFsaWRfdXNlcm5hbWV9OntwYXNzd29yZH0=","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"roundId\": \"6a95ba3a-1448-4824-998c-045552421f62\",\n    \"providerRoundId\": \"providerRoundId\",\n    \"isRoundFinished\": true,\n    \"currency\": \"TRY\",\n    \"provider\": \"provider\",\n    \"gameId\": \"234f4893-6bdc-4dea-82bb-6e351976836e\",\n    \"timestamp\": 1710772705668,\n    \"session\": {\n        \"externalId\": \"your-session-id\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\" : 2,\n    \"errorMessage\" : \"Invalid credentials\"\n}"}],"_postman_id":"cbefb9a0-e5d4-4323-9cfa-8ebcf833370b"},{"name":"Free Spins Completed","id":"f00b76ed-103d-4c0e-b03e-29812f22b3e6","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"externalFreeSpinsId\": \"your-free-spins-id\",\n    \"totalWinAmount\": 100,\n    \"currency\": \"USD\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/free-spins-completed","description":"<p>Called to notify about free spins completion.</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>internalUserId</code> (string, required) - User id in aggregator provider system</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>externalFreeSpinsId</code> (string, required) - Free spins id that you used for its create</p>\n</li>\n<li><p><code>currency</code> (enum, required) - Currency of rpvodied amounts</p>\n</li>\n<li><p><code>totalWinAmount</code> (long, required) - Total winning amount of a free spin</p>\n</li>\n<li><p><code>txId</code> (string, required) - Free spins total win transaction id for operation idempotency</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>balance</code> (long, required) - In Money format</p>\n</li>\n<li><p><code>currency</code> (string, required) - User currency</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["free-spins-completed"],"host":["{callbackUrl}"],"query":[],"variable":[]}},"response":[{"id":"a3e1a3a3-1196-4efc-9818-cccb765a8d6d","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"externalFreeSpinsId\": \"your-free-spins-id\",\n    \"totalWinAmount\": 100,\n    \"currency\": \"USD\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"externalUserId\": \"externalId\",\n    \"balance\": 100000,\n    \"currency\": \"TRY\"\n}"},{"id":"07ba1e4f-e2c4-4604-81e8-1b06094720f3","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e2ludmFsaWRfdXNlcm5hbWV9OntwYXNzd29yZH0=","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"internalUserId\": \"037ee5a8-d09f-4b0a-9f5d-dc5d12d0d48b\",\n    \"externalUserId\": \"externalId\",\n    \"externalFreeSpinsId\": \"your-free-spins-id\",\n    \"totalWinAmount\": 100,\n    \"currency\": \"USD\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\" : 2,\n    \"errorMessage\" : \"Invalid credentials\"\n}"}],"_postman_id":"f00b76ed-103d-4c0e-b03e-29812f22b3e6"},{"name":"Get Player Details (Optional)","id":"02290260-8127-4001-ae44-04f780841fe2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"token\": \"some-token\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/get-player-details","description":"<p>Called to fetch player details by provided token.</p>\n<p>This API is optional, it might become mandatory to be implemented depending on the product scope received by the casino</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider</p>\n</li>\n<li><p><code>token</code> (string, required) - Token received from integration that will allow it to fetch player details</p>\n</li>\n</ul>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>externalUserId</code> (string, required) - User id in casino system</p>\n</li>\n<li><p><code>username</code> (string, required)</p>\n</li>\n<li><p><code>name</code> (string, optional)</p>\n</li>\n<li><p><code>surname</code> (string, optional)</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Values: 'Mr', 'Mrs', 'Ms', 'Miss'</p>\n</li>\n</ul>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}},"urlObject":{"path":["get-player-details"],"host":["{callbackUrl}"],"query":[],"variable":[]}},"response":[{"id":"2b6a6c2f-0fa7-49c2-9630-c0f530511c86","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"token\": \"some-token\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"externalUserId\": \"externalId\",\n  \"username\": \"username\",\n  \"name\": \"Name\",\n  \"surname\": \"Surname\",\n  \"honorific\": null\n}"},{"id":"46c0e901-cdd6-4e8b-b983-975fcb8d3cad","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e2ludmFsaWRfdXNlcm5hbWV9OntwYXNzd29yZH0=","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"token\": \"some-token\"\n}","options":{"raw":{"language":"json"}}},"url":"{callbackUrl}/end-round"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\" : 2,\n    \"errorMessage\" : \"Invalid credentials\"\n}"}],"_postman_id":"02290260-8127-4001-ae44-04f780841fe2"}],"id":"8cf8d392-ab55-4c73-ac34-2d9330409293","description":"<p>Requests sent from Aggregator Provider to Casino</p>\n","event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"c6590a27-dc88-4b63-a79f-301d59369022"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"62352c3c-1aea-4a4b-b976-80b190303b8f"}}],"_postman_id":"8cf8d392-ab55-4c73-ac34-2d9330409293","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","name":"Casino Aggregator API","type":"folder"}}}],"id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"f6f7c879-aa4e-4886-9d19-12b839cc4787"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"86f94022-fff1-4a32-8bb4-967edd8fd12b"}}],"_postman_id":"28e4b9aa-5074-4e38-a307-dc748b3b33b8","description":""},{"name":"Sportsbook Scheme","item":[{"name":"Transaction Details","item":[],"id":"4a13db02-fd13-4fca-aac0-fe7094548113","description":"<h2 id=\"transaction-details\">Transaction Details</h2>\n<p>Schema of the <code>details</code> object attached to sportsbook-originated <code>Transaction</code> and <code>End Round</code> callbacks.</p>\n<p>Populated only for sportsbook transactions; null for casino game transactions.</p>\n<hr />\n<h4 id=\"object\">Object</h4>\n<ul>\n<li><p><code>method</code> (enum, required) - Sportsbook event that triggered the notify. Values: 'ACCOUNT_DETAILS', 'EDIT_BET', 'BET_CANCELED', 'CREATE_BET_BATCH', 'CREATE_BET', 'BET_SETTLED', 'BET_CASH_OUT', 'BET_PARTIAL_CASH_OUT', 'BET_CREATE_FAILED', 'BET_ODDS_BOOST_SETTLED', 'BET_ODDS_BOOST_CANCELED', 'CREATE_FORECAST', 'SETTLE_FORECAST', 'CANCEL_FORECAST'</p>\n</li>\n<li><p><code>bet</code> (object, required) - Snapshot of the underlying sportsbook bet (see Bet section below)</p>\n</li>\n<li><p><code>bonus</code> (object, optional) - Bonus associated with a transaction</p>\n<ul>\n<li><code>playerBonusId</code> (string, required) - Identifier of a player bonus</li>\n</ul>\n</li>\n</ul>\n<p>Bet (<code>details.bet</code>):</p>\n<ul>\n<li><p><code>betId</code> (string, required) - Bet id in sportsbook system</p>\n</li>\n<li><p><code>totalCoefficient</code> (double, required) - Total bet coefficient</p>\n</li>\n<li><p><code>eventPicks</code> (array, required) - Picks placed on regular sport events (see Event Pick section)</p>\n</li>\n<li><p><code>outrightPicks</code> (array, required) - Picks placed on outright (long-term) markets (see Outright Pick section)</p>\n</li>\n<li><p><code>createTime</code> (long, required) - Timestamp in milliseconds when the bet was placed</p>\n</li>\n<li><p><code>anyPickForLiveEvent</code> (boolean, required) - True if at least one pick in the bet was placed on a live event</p>\n</li>\n<li><p><code>betStructure</code> (object, required) - Structural summary of the bet (see \"Bet Structure\" section in this folder)</p>\n</li>\n<li><p><code>result</code> (enum, optional) - Bet settlement state. Null while the bet is still pending. Values: 'WIN', 'LOSS', 'PARTIAL_WIN', 'PARTIAL_LOSS', 'CANCELED', 'PENDING', 'CASH_OUTED', 'RETURN', 'UNKNOWN'</p>\n</li>\n<li><p><code>settledAt</code> (long, optional) - Timestamp in milliseconds when the bet was settled</p>\n</li>\n<li><p><code>cashOutAt</code> (long, optional) - Timestamp in milliseconds when the bet was cashed out</p>\n</li>\n<li><p><code>canceledAt</code> (long, optional) - Timestamp in milliseconds when the bet was canceled</p>\n</li>\n</ul>\n<p>Event Pick (<code>details.bet.eventPicks[]</code>):</p>\n<ul>\n<li><p><code>pickId</code> (string, required) - Pick id in sportsbook system</p>\n</li>\n<li><p><code>sportName</code> (string, required) - Sport name. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Sport name is a free-form string aligned with the codes in the Sports section below.</p>\n</li>\n<li><p><code>sportId</code> (string, required) - Sport id (UUID). See the <strong>Sports</strong> section below for the full id → code mapping.</p>\n</li>\n<li><p><code>categoryName</code> (string, required) - Sport category name</p>\n</li>\n<li><p><code>categoryId</code> (string, required) - Sport category id</p>\n</li>\n<li><p><code>tournamentName</code> (string, required) - Tournament name</p>\n</li>\n<li><p><code>tournamentId</code> (string, required) - Tournament id</p>\n</li>\n<li><p><code>coefficient</code> (string, required) - Pick coefficient</p>\n</li>\n<li><p><code>result</code> (string, required) - Pick settlement result. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Values:</p>\n<ul>\n<li><p><code>no_result</code> - pick not settled yet</p>\n</li>\n<li><p><code>win</code> - pick won; payout = <code>coefficient</code></p>\n</li>\n<li><p><code>loss</code> - pick lost; payout = 0</p>\n</li>\n<li><p><code>half_win</code> - half of stake wins at full odds, the other half returns; payout = <code>(coefficient + 1) / 2</code></p>\n</li>\n<li><p><code>half_loss</code> - half of stake lost, the other half returns; payout = <code>1 / 2</code></p>\n</li>\n<li><p><code>_return</code> - stake refunded; payout = <code>1</code></p>\n</li>\n<li><p><code>void</code> - pick voided (e.g. cash-out); payout determined separately</p>\n</li>\n<li><p><code>partial_win::</code> - dynamic value emitted when the pick partially won at the given coefficient (the part after <code>::</code> is the actual coefficient, e.g. <code>partial_win::1.85</code>). Parse the prefix <code>partial_win::</code> and extract the trailing number.</p>\n</li>\n</ul>\n</li>\n<li><p><code>banker</code> (boolean, required) - True if the pick is marked as a banker in a system bet</p>\n</li>\n<li><p><code>contribution</code> (double, optional) - Pick contribution to the total coefficient</p>\n</li>\n<li><p><code>eventStatus</code> (enum, required) - Sport event status. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Values:</p>\n<ul>\n<li><p><code>not_started</code></p>\n</li>\n<li><p><code>in_progress</code></p>\n</li>\n<li><p><code>finished</code></p>\n</li>\n<li><p><code>cancelled</code></p>\n</li>\n<li><p><code>interrupted</code></p>\n</li>\n<li><p><code>postponed</code></p>\n</li>\n<li><p><code>retired</code></p>\n</li>\n<li><p><code>corrupted</code></p>\n</li>\n</ul>\n</li>\n<li><p><code>eventId</code> (string, required) - Sport event id</p>\n</li>\n<li><p><code>eventName</code> (string, required) - Sport event name</p>\n</li>\n<li><p><code>outcome</code> (object, required) - Outcome descriptor identifying which market the pick was placed on and which outcome was selected (see \"Outcome\" section in this folder).</p>\n</li>\n<li><p><code>participants</code> (object, required) - Map keyed by participant slot, value is a Participant object with <code>name</code> (string) and <code>teamId</code> (string, UUID).</p>\n</li>\n<li><p><code>finalScore</code> (object, optional) - Final score of the event with <code>team1</code> (float) and <code>team2</code> (float).</p>\n</li>\n</ul>\n<p>Outright Pick (<code>details.bet.outrightPicks[]</code>):</p>\n<ul>\n<li><p><code>pickId</code> (string, required) - Pick id in sportsbook system</p>\n</li>\n<li><p><code>sportName</code> (string, required) - Sport name. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Sport name is a free-form string aligned with the codes in the Sports section below.</p>\n</li>\n<li><p><code>sportId</code> (string, required) - Sport id (UUID). See the <strong>Sports</strong> section below for the full id → code mapping.</p>\n</li>\n<li><p><code>categoryName</code> (string, required) - Sport category name</p>\n</li>\n<li><p><code>categoryId</code> (string, required) - Sport category id</p>\n</li>\n<li><p><code>tournamentName</code> (string, required) - Tournament name</p>\n</li>\n<li><p><code>tournamentId</code> (string, required) - Tournament id</p>\n</li>\n<li><p><code>coefficient</code> (string, required) - Pick coefficient</p>\n</li>\n<li><p><code>result</code> (string, required) - Pick settlement result. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Values:</p>\n<ul>\n<li><p><code>no_result</code> - pick not settled yet</p>\n</li>\n<li><p><code>win</code> - pick won; payout = <code>coefficient</code></p>\n</li>\n<li><p><code>loss</code> - pick lost; payout = 0</p>\n</li>\n<li><p><code>half_win</code> - half of stake wins at full odds, the other half returns; payout = <code>(coefficient + 1) / 2</code></p>\n</li>\n<li><p><code>half_loss</code> - half of stake lost, the other half returns; payout = <code>1 / 2</code></p>\n</li>\n<li><p><code>_return</code> - stake refunded; payout = <code>1</code></p>\n</li>\n<li><p><code>void</code> - pick voided (e.g. cash-out); payout determined separately</p>\n</li>\n<li><p><code>partial_win::</code> - dynamic value emitted when the pick partially won at the given coefficient (the part after <code>::</code> is the actual coefficient, e.g. <code>partial_win::1.85</code>). Parse the prefix <code>partial_win::</code> and extract the trailing number.</p>\n</li>\n</ul>\n</li>\n<li><p><code>banker</code> (boolean, required) - True if the pick is marked as a banker in a system bet</p>\n</li>\n<li><p><code>contribution</code> (double, optional) - Pick contribution to the total coefficient</p>\n</li>\n<li><p><code>outcomeParameterHash</code> (object, required) - Outcome descriptor for the outright market.</p>\n</li>\n<li><p><code>outrightId</code> (string, required) - Outright market id</p>\n</li>\n<li><p><code>outrightName</code> (string, required) - Outright market name</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"example-payload\">Example payload</h4>\n<p>Bet on Kylian Mbappe (Real Madrid, team p1) to score over 1.5 goals in the full match against Manchester City. Market <code>score_oupt</code> from group <code>oupt</code>.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"method\": \"BET_SETTLED\",\n  \"bet\": {\n    \"betId\": \"b1f8a8a4-2eb3-4b16-8d6c-2a4a25c5c5c5\",\n    \"totalCoefficient\": 2.10,\n    \"eventPicks\": [\n      {\n        \"pickId\": \"1c1a8a01-1111-4111-9111-111111111111\",\n        \"sportName\": \"soccer\",\n        \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\",\n        \"categoryName\": \"International Clubs\",\n        \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n        \"tournamentName\": \"UEFA Champions League\",\n        \"tournamentId\": \"33333333-3333-3333-3333-333333333333\",\n        \"coefficient\": \"2.10\",\n        \"result\": \"win\",\n        \"banker\": false,\n        \"contribution\": null,\n        \"eventStatus\": \"finished\",\n        \"eventId\": \"44444444-4444-4444-4444-444444444444\",\n        \"eventName\": \"Real Madrid vs Manchester City\",\n        \"outcome\": {\n          \"scopeName\": \"normal_time\",\n          \"scopeNumber\": 0,\n          \"scoreType\": \"score\",\n          \"marketGroup\": \"oupt\",\n          \"marketParameters\": {\n            \"player\": \"kylian_mbappe\",\n            \"team\": \"p1\",\n            \"total\": \"1.5\"\n          },\n          \"outcomeParameters\": {\n            \"@kind\": \"enum\",\n            \"outcome\": \"over\"\n          }\n        },\n        \"participants\": {\n          \"1\": { \"name\": \"Real Madrid\", \"teamId\": \"55555555-5555-5555-5555-555555555555\" },\n          \"2\": { \"name\": \"Manchester City\", \"teamId\": \"66666666-6666-6666-6666-666666666666\" }\n        },\n        \"finalScore\": { \"team1\": 2.0, \"team2\": 1.0 }\n      }\n    ],\n    \"outrightPicks\": [],\n    \"createTime\": 1710849600000,\n    \"anyPickForLiveEvent\": false,\n    \"betStructure\": { \"betType\": \"SINGLE\", \"totalPicks\": 1, \"picksPerSelection\": [1], \"bankersCount\": 0 },\n    \"result\": \"win\",\n    \"settledAt\": 1710856800000,\n    \"cashOutAt\": null,\n    \"canceledAt\": null\n  }\n}\n\n</code></pre>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"4992d7cf-ea0f-4444-8bf9-9d7bcf5bf58a"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"950efc47-5495-4a42-8dac-41ccce8390c7"}}],"_postman_id":"4a13db02-fd13-4fca-aac0-fe7094548113"},{"name":"Bet Structure","item":[],"id":"4e1b9162-53b8-48b5-8ce1-85d068dba43b","description":"<h2 id=\"bet-structure\">Bet Structure</h2>\n<p>Structural summary of a bet, exposed at <code>details.bet.betStructure</code>.</p>\n<p>The platform represents bet structure with a compact string (e.g. <code>1/1</code>, <code>3/3</code>, <code>2/3</code>, <code>2/3:3/3</code>, <code>2/3|B1</code>). This object exposes the same information as parsed values, so an integration does not need to parse the string itself.</p>\n<hr />\n<h4 id=\"object\">Object</h4>\n<ul>\n<li><p><code>betType</code> (enum, required) - Bet structure. Values: 'SINGLE' (one pick), 'PARLAY' (all picks must win), 'SYSTEM' (any K out of N must win, possibly across several selection groups).</p>\n</li>\n<li><p><code>totalPicks</code> (int, required) - Total number of picks <code>N</code> in the bet.</p>\n</li>\n<li><p><code>picksPerSelection</code> (array, required) - For each selection group, the number of picks <code>K</code> that must win for that group to pay out. SINGLE/PARLAY have one entry equal to <code>totalPicks</code>; SYSTEM may have several entries with <code>K &lt; N</code>.</p>\n</li>\n<li><p><code>bankersCount</code> (int, required) - Number of picks marked as bankers. Bankers must always win for any combination to settle.</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"reading-picksperselection\">Reading <code>picksPerSelection</code></h4>\n<p>Each entry is the <code>K</code> of a <code>K/N</code> selection group. The number of winning combinations the bet pays out on equals <code>sum over K of C(N, K)</code>.</p>\n<p>Examples:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Bet structure</th>\n<th><code>betType</code></th>\n<th><code>totalPicks</code></th>\n<th><code>picksPerSelection</code></th>\n<th><code>bankersCount</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Single (<code>1/1</code>)</td>\n<td>SINGLE</td>\n<td>1</td>\n<td><code>[1]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>Accumulator on 3 picks (<code>3/3</code>)</td>\n<td>PARLAY</td>\n<td>3</td>\n<td><code>[3]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>2-of-3 system (<code>2/3</code>)</td>\n<td>SYSTEM</td>\n<td>3</td>\n<td><code>[2]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>Trixie (<code>2/3:3/3</code>)</td>\n<td>SYSTEM</td>\n<td>3</td>\n<td><code>[2, 3]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>Patent (<code>1/3:2/3:3/3</code>)</td>\n<td>SYSTEM</td>\n<td>3</td>\n<td><code>[1, 2, 3]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>Yankee (<code>2/4:3/4:4/4</code>)</td>\n<td>SYSTEM</td>\n<td>4</td>\n<td><code>[2, 3, 4]</code></td>\n<td>0</td>\n</tr>\n<tr>\n<td>System with 3 banker picks(3/4|B3)</td>\n<td>SYSTEM</td>\n<td>7</td>\n<td><code>[3]</code></td>\n<td>3</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"ece11d39-d979-460d-b5e0-cd60832181d1"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"eb5ec529-3b15-42a2-8e65-05a70e0f8602"}}],"_postman_id":"4e1b9162-53b8-48b5-8ce1-85d068dba43b"},{"name":"Outcome","item":[],"id":"82926e1c-fd81-43d2-989d-c165c3b99fdb","description":"<h2 id=\"outcome\">Outcome</h2>\n<p>Outcome descriptor attached to an Event Pick (<code>details.bet.eventPicks[].outcome</code>). Identifies which market the pick was placed on and which outcome of that market was selected.</p>\n<hr />\n<h4 id=\"object\">Object</h4>\n<ul>\n<li><p><code>scopeName</code> (enum, required) - Scope of the event the market refers to (which segment of the event the score / metric is measured over). <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Values:</p>\n<ul>\n<li><code>half</code></li>\n<li><code>full_event</code></li>\n<li><code>normal_time</code></li>\n<li><code>period</code></li>\n<li><code>over_times</code></li>\n<li><code>over_time</code></li>\n<li><code>penalties</code></li>\n<li><code>penalty</code></li>\n<li><code>quarter</code></li>\n<li><code>set</code></li>\n<li><code>game</code></li>\n<li><code>frame</code></li>\n<li><code>round</code></li>\n<li><code>inning</code></li>\n<li><code>sudden_death</code></li>\n<li><code>kicking_competition</code></li>\n<li><code>half_time</code></li>\n<li><code>half_time_overtime</code></li>\n<li><code>end_break</code></li>\n<li><code>set_break</code></li>\n<li><code>time_out</code></li>\n<li><code>technical_time_out</code></li>\n<li><code>medical_time_out</code></li>\n<li><code>quarter_break</code></li>\n<li><code>overtime_break</code></li>\n<li><code>intermission</code></li>\n<li><code>pause</code></li>\n<li><code>interval</code></li>\n<li><code>lunch_break</code></li>\n<li><code>tea_break</code></li>\n<li><code>break</code></li>\n<li><code>rest</code></li>\n<li><code>change_ends</code></li>\n<li><code>map</code></li>\n<li><code>extra_inning</code></li>\n<li><code>over</code></li>\n<li><code>delivery</code></li>\n<li><code>session</code></li>\n<li><code>super_over</code></li>\n</ul>\n</li>\n<li><p><code>scopeNumber</code> (int, required) - Ordinal of the scope inside the event. <code>half=1</code> → first half, <code>period=2</code> → second period, <code>set=3</code> → third set. For scopes that occur once per event (e.g. <code>full_event</code>, <code>normal_time</code>) typically <code>0</code>.</p>\n</li>\n<li><p><code>scoreType</code> (enum, required) - Metric the market is built on. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> Values:</p>\n<ul>\n<li><code>score</code></li>\n<li><code>yellow_card</code></li>\n<li><code>red_card</code></li>\n<li><code>corner</code></li>\n<li><code>offside</code></li>\n<li><code>sub</code></li>\n<li><code>time</code></li>\n<li><code>shots</code></li>\n<li><code>throw_in</code></li>\n<li><code>woodwork</code></li>\n<li><code>goal_kick</code></li>\n<li><code>save</code></li>\n<li><code>ast</code></li>\n<li><code>tkl</code></li>\n<li><code>foul_c</code></li>\n<li><code>foul_d</code></li>\n<li><code>reb</code></li>\n<li><code>free_throw</code></li>\n<li><code>pt3</code></li>\n<li><code>pt2</code></li>\n<li><code>point</code></li>\n<li><code>game</code></li>\n<li><code>shot_on_goal</code></li>\n<li><code>foul</code></li>\n<li><code>winner_number</code></li>\n<li><code>place_number</code></li>\n<li><code>fact</code></li>\n<li><code>s4</code></li>\n<li><code>s6</code></li>\n<li><code>boundary</code></li>\n<li><code>wicket</code></li>\n<li><code>wicket_or_boundary</code></li>\n<li><code>runout</code></li>\n<li><code>extra</code></li>\n<li><code>maiden</code></li>\n<li><code>performance</code></li>\n<li><code>ball</code></li>\n<li><code>knock_down</code></li>\n<li><code>gm</code></li>\n<li><code>victory</code></li>\n<li><code>penalty</code></li>\n<li><code>draw</code></li>\n<li><code>loss</code></li>\n<li><code>to_nil</code></li>\n</ul>\n</li>\n<li><p><code>marketGroup</code> (enum, required) - Market family the pick belongs to. <strong>New values may be added over time. Integrators MUST NOT declare a closed enum with exactly these values on their side; treat the field as an open string and handle unknown values gracefully so the integration does not break when a new value is introduced.</strong> The same applies to the <code>marketParameters</code> and <code>outcomeParameters</code> maps listed under each marketGroup below — new keys may appear in the map, and new values may appear for an existing key (including the outcome <code>kind</code> value). Treat both keys and values as open: never declare a closed enum on the integrator side, and skip unknown entries without failing. Values:</p>\n<ul>\n<li><code>1x2</code><ul>\n<li>description: Market with 3 outcomes. 1st outcome: win home_team, 2nd draw, 3rd win away_team</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>1x2_ou</code><ul>\n<li>description: Combined market: match result (1x2) and total over/under.</li>\n<li>marketParameters: <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_enum, outcome=p1_over</li>\n<li>kind=id_enum, outcome=p1_under</li>\n<li>kind=enum, outcome=draw_over</li>\n<li>kind=enum, outcome=draw_under</li>\n<li>kind=id_enum, outcome=p2_over</li>\n<li>kind=id_enum, outcome=p2_under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>1x2_teams_to_score</code><ul>\n<li>description: Who wins the match and witch teams to score. Only team that has won scores or both? If draw the same</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_enum, outcome=p1_both</li>\n<li>kind=id_id, outcome=p1_p1</li>\n<li>kind=enum, outcome=draw_both</li>\n<li>kind=enum, outcome=draw_none</li>\n<li>kind=id_enum, outcome=p2_both</li>\n<li>kind=id_id, outcome=p2_p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>1x2_early_payout</code><ul>\n<li>description: Market with 3 outcomes. 1st outcome: win home_team, 2nd draw, 3rd win away_team</li>\n<li>marketParameters: <code>rp</code> (example: <code>5</code>), <code>sd</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>win_most_periods</code><ul>\n<li>description: Which team wins the most periods, or tie.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>triple_result</code><ul>\n<li>description: Result of each of 3 periods combined (all 27 permutations of P1/X/P2).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=period123, period1=p1, period2=p1, period3=p1</li>\n<li>kind=period123, period1=p1, period2=p1, period3=draw</li>\n<li>kind=period123, period1=p1, period2=p1, period3=p2</li>\n<li>kind=period123, period1=p1, period2=draw, period3=p1</li>\n<li>kind=period123, period1=p1, period2=draw, period3=draw</li>\n<li>kind=period123, period1=p1, period2=draw, period3=p2</li>\n<li>kind=period123, period1=p1, period2=p2, period3=p1</li>\n<li>kind=period123, period1=p1, period2=p2, period3=draw</li>\n<li>kind=period123, period1=p1, period2=p2, period3=p2</li>\n<li>kind=period123, period1=draw, period2=p1, period3=p1</li>\n<li>kind=period123, period1=draw, period2=p1, period3=draw</li>\n<li>kind=period123, period1=draw, period2=p1, period3=p2</li>\n<li>kind=period123, period1=draw, period2=draw, period3=p1</li>\n<li>kind=period123, period1=draw, period2=draw, period3=draw</li>\n<li>kind=period123, period1=draw, period2=draw, period3=p2</li>\n<li>kind=period123, period1=draw, period2=p2, period3=p1</li>\n<li>kind=period123, period1=draw, period2=p2, period3=draw</li>\n<li>kind=period123, period1=draw, period2=p2, period3=p2</li>\n<li>kind=period123, period1=p2, period2=p1, period3=p1</li>\n<li>kind=period123, period1=p2, period2=p1, period3=draw</li>\n<li>kind=period123, period1=p2, period2=p1, period3=p2</li>\n<li>kind=period123, period1=p2, period2=draw, period3=p1</li>\n<li>kind=period123, period1=p2, period2=draw, period3=draw</li>\n<li>kind=period123, period1=p2, period2=draw, period3=p2</li>\n<li>kind=period123, period1=p2, period2=p2, period3=p1</li>\n<li>kind=period123, period1=p2, period2=p2, period3=draw</li>\n<li>kind=period123, period1=p2, period2=p2, period3=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>winning_margin</code><ul>\n<li>description: Winning margin: exact score difference (1, 2, or more than 2).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=gt</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>winning_margin_yn</code><ul>\n<li>description: Either Team to Win By {{number}} Goals</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>longest_consecutive</code><ul>\n<li>description: Longest Consecutive points</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=value, outcome=4, predicate=eq</li>\n<li>kind=value, outcome=5, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_race</code><ul>\n<li>description: Who first scores one goal and seven goals, or another specified amount</li>\n<li>marketParameters: <code>number</code> (example: <code>1,7</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p1</li>\n<li>kind=id_sequence, outcome=p1,p2</li>\n<li>kind=id_sequence, outcome=p2,p1</li>\n<li>kind=id_sequence, outcome=p2,p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race</code><ul>\n<li>description: First To Score {{number}} Goals</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=no</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>scopes_with_result</code><ul>\n<li>description: How many scopes will be finished with outcome specified in market parameter</li>\n<li>marketParameters: <code>score</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=0, predicate=eq</li>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>scopes_with_total</code><ul>\n<li>description: How many scopes will be finished with specified total</li>\n<li>marketParameters: <code>total</code> (example: <code>19</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=0, predicate=eq</li>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>score_count</code><ul>\n<li>description: How many arrows will hit the target to the specified score area</li>\n<li>marketParameters: <code>score</code> (example: <code>8</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=0, predicate=eq</li>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=value, outcome=4, predicate=eq</li>\n<li>kind=value, outcome=5, predicate=eq</li>\n<li>kind=value, outcome=6, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>interval_1x2</code><ul>\n<li>description: Market with 3 outcomes. 1st outcome: win home_team, 2nd draw, 3rd win away_team. Score selected from time range.</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>10</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>12</code><ul>\n<li>description: Win home or away. This market used in sports where draw outcome doesn't exist</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>12_score</code><ul>\n<li>description: Kiron table tennis is played until score reaches 7. But if score 6:6 player should score 2 goals to win 6:8, or 7:9 etc</li>\n<li>marketParameters: <code>score</code> (example: <code>7</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_enum, outcome=p2_equal</li>\n<li>kind=id_enum, outcome=p1_over</li>\n<li>kind=id_enum, outcome=p2_equal</li>\n<li>kind=id_enum, outcome=p2_over</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>dc</code><ul>\n<li>description: Double chance. 3 outcomes: DRAW or Win home_team / No DRAW / Draw or Win away_team.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_enum, outcome=p1_draw</li>\n<li>kind=id_enum, outcome=p2_draw</li>\n<li>kind=enum, outcome=no_draw</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>interval_dc</code><ul>\n<li>description: Double chance. 3 outcomes: DRAW or Win home_team / No DRAW / Draw or Win away_team. Score selected from time range.</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>10</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_enum, outcome=p1_draw</li>\n<li>kind=id_enum, outcome=p2_draw</li>\n<li>kind=enum, outcome=no_draw</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ah</code><ul>\n<li><p>description:</p>\n<p>  Asian handicap. The 'team' parameter is always p1; for p2 the handicap sign is inverted automatically.\n  The 'handicap' parameter determines the settlement type:</p>\n<ol>\n<li><p>HARD handicap (x.5, e.g. -1.5, +0.5, +2.5):\nOnly win or loss. Handicap is added to the team's score; if adjusted score &gt; opponent → win, otherwise → loss.\nExample: handicap=-1.5, score 1:3 → 1:(3-1.5)=1:1.5 → p2 wins. score 1:2 → 1:(2-1.5)=1:0.5 → p2 loses.</p>\n</li>\n<li><p>SOFT handicap (x.0, e.g. -2.0, 0.0, +1.0):\nWin, loss, or return. Same as hard but when adjusted scores are equal → return (stake refunded).\nExample: handicap=-2, score 1:3 → 1:(3-2)=1:1 → return. score 1:4 → 1:2 → p2 wins. score 1:2 → 1:0 → p2 loses.\nSpecial case ZERO handicap (0.0): team wins → win, draw → return, team loses → loss.</p>\n</li>\n<li><p>QUARTER handicap (x.25 or x.75, e.g. -0.25, +1.75, +2.25):\nSplit into two equal bets: soft (x.0) and hard (x.5). E.g. handicap=1.25 splits to 1.0(soft) + 1.5(hard).\nCombined result via matrix: soft=return+hard=win → half_win, soft=return+hard=loss → half_loss,\nsoft=win+hard=win → win, soft=loss+hard=loss → loss.\nExample: handicap=+0.25 splits to 0.0 and +0.5. Score 1:1 → soft(0.0)=return, hard(+0.5)=win → half_win.\nScore 0:1 → soft(0.0)=loss, hard(+0.5)=loss → loss.</p>\n</li>\n</ol>\n<p>  Possible results: win, loss, half_win, half_loss, return.</p>\n</li>\n<li><p>marketParameters: <code>team</code> (example: <code>p1</code>), <code>handicap</code> (example: <code>2.75</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>interval_ah</code><ul>\n<li><p>description:</p>\n<p>  Asian handicap in the time interval (minutes. The 'team' parameter is always p1; for p2 the handicap sign is inverted automatically.\n  The 'handicap' parameter determines the settlement type:</p>\n<ol>\n<li><p>HARD handicap (x.5, e.g. -1.5, +0.5, +2.5):\nOnly win or loss. Handicap is added to the team's score; if adjusted score &gt; opponent → win, otherwise → loss.\nExample: handicap=-1.5, score 1:3 → 1:(3-1.5)=1:1.5 → p2 wins. score 1:2 → 1:(2-1.5)=1:0.5 → p2 loses.</p>\n</li>\n<li><p>SOFT handicap (x.0, e.g. -2.0, 0.0, +1.0):\nWin, loss, or return. Same as hard but when adjusted scores are equal → return (stake refunded).\nExample: handicap=-2, score 1:3 → 1:(3-2)=1:1 → return. score 1:4 → 1:2 → p2 wins. score 1:2 → 1:0 → p2 loses.\nSpecial case ZERO handicap (0.0): team wins → win, draw → return, team loses → loss.</p>\n</li>\n<li><p>QUARTER handicap (x.25 or x.75, e.g. -0.25, +1.75, +2.25):\nSplit into two equal bets: soft (x.0) and hard (x.5). E.g. handicap=1.25 splits to 1.0(soft) + 1.5(hard).\nCombined result via matrix: soft=return+hard=win → half_win, soft=return+hard=loss → half_loss,\nsoft=win+hard=win → win, soft=loss+hard=loss → loss.\nExample: handicap=+0.25 splits to 0.0 and +0.5. Score 1:1 → soft(0.0)=return, hard(+0.5)=win → half_win.\nScore 0:1 → soft(0.0)=loss, hard(+0.5)=loss → loss.</p>\n</li>\n</ol>\n<p>  Possible results: win, loss, half_win, half_loss, return.</p>\n</li>\n<li><p>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>10</code>), <code>team</code> (example: <code>p1</code>), <code>handicap</code> (example: <code>2.75</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ou</code><ul>\n<li>description: Total over/under</li>\n<li>marketParameters: <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ou_team</code><ul>\n<li>description: Total over/under for team.</li>\n<li>marketParameters: <code>total</code> (example: <code>3.5</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>interval_ou</code><ul>\n<li>description: Total over/under. Score selected from time range.</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>10</code>), <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>interval_ou_team</code><ul>\n<li>description: Total over/under for team. Score selected from time range.</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>10</code>), <code>total</code> (example: <code>3.5</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>cs</code><ul>\n<li>description: Correct score in scope for both teams.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=key_id, p1=0, p2=0</li>\n<li>kind=key_id, p1=1, p2=0</li>\n<li>kind=key_id, p1=2, p2=0</li>\n<li>kind=key_id, p1=2, p2=1</li>\n<li>kind=key_id, p1=2, p2=2</li>\n<li>kind=key_id, p1=0, p2=1</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>aft_scp</code><ul>\n<li>description: score after first 2 maps played</li>\n<li>marketParameters: <code>scope</code> (example: <code>map</code>), <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=key_id, p1=2, p2=0</li>\n<li>kind=key_id, p1=1, p2=1</li>\n<li>kind=key_id, p1=0, p2=2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>fin_num_yn</code><ul>\n<li>description: The number in the final score</li>\n<li>marketParameters: <code>number</code> (example: <code>1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_hlvs_yn</code><ul>\n<li>description: Goals in Both Halves</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_frst_one_scnd_yn</code><ul>\n<li>description: Both teams to score in 1st half and at least one not to score in 2nd</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_either_half_yn</code><ul>\n<li>description: Both teams to score at least in one half</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>draw_either_half_yn</code><ul>\n<li>description: Draw in either half</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>each_win_one_half_yn</code><ul>\n<li>description: Each team to win one half</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>one_half_only_ynt</code><ul>\n<li>description: Team To score in only one of halves</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_n_win_ynt</code><ul>\n<li>description: Team will score first goal and win</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_n_lose_ynt</code><ul>\n<li>description: Team will score first goal and lose</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_n_draw_ynt</code><ul>\n<li>description: Team will score first goal and draw</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_n_no_win_ynt</code><ul>\n<li>description: Team will score first goal and not win</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>dur_match</code><ul>\n<li>description: During match score is</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=key_id, p1=1, p2=1</li>\n<li>kind=key_id, p1=2, p2=0</li>\n<li>kind=key_id, p1=0, p2=2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_in_row_yn</code><ul>\n<li>description: Either Team to Score {{number}} Goals In A Row</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_in_row_ynt</code><ul>\n<li>description: To Score {{number}} Goals In A Row, {{teamName}}</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>either_to_score_x_more_yn</code><ul>\n<li>description: Either Team to Score {{number}} or More Goals</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_yn</code><ul>\n<li>description: Substitution to score</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>custom</code><ul>\n<li>description: Custom market</li>\n<li>marketParameters: <code>id</code> (example: <code>UUID</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=custom, id=UUID</li>\n<li>kind=custom, id=UUID</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>odd_even</code><ul>\n<li>description: Outcome win when total score for both teams of the scope is odd or even.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>odd_even_high_low</code><ul>\n<li>description: Combination of odd even and over under for tennis</li>\n<li>marketParameters: <code>total</code> (example: <code>10.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd_low</li>\n<li>kind=enum, outcome=odd_high</li>\n<li>kind=enum, outcome=even_low</li>\n<li>kind=enum, outcome=even_high</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>odd_even_team</code><ul>\n<li>description: Outcome win when total score for team of the scope is odd or even.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>u_win_draw_team</code><ul>\n<li>description: Team total under x and team win or draw.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>u_win_team</code><ul>\n<li>description: Team total under x and team win.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>o_win_team</code><ul>\n<li>description: Team total over and team win.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>o_win_draw_team</code><ul>\n<li>description: Team total over x and team win or draw.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>2.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>u_draw</code><ul>\n<li>description: Score in scope will be draw AND over x</li>\n<li>marketParameters: <code>total</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>o_draw</code><ul>\n<li>description: Score in scope will be draw AND over x</li>\n<li>marketParameters: <code>total</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>win_to_nil_team</code><ul>\n<li>description: Outcome yes win when team win scope and enemy don't score.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>range_number</code><ul>\n<li>description: Score of the match: range number</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=range, from=1, to=2</li>\n<li>kind=value, outcome=3, predicate=gte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>range_number_team</code><ul>\n<li>description: Score of the match: range number.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=range, from=1, to=2</li>\n<li>kind=value, outcome=3, predicate=gte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>range_number_yes_no</code><ul>\n<li>description: Range number of goals: yes / no</li>\n<li>marketParameters: <code>from</code> (example: <code>5</code>), <code>to</code> (example: <code>7</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>range_number_yes_no_team</code><ul>\n<li>description: Range number of goals: yes / no Chelsea</li>\n<li>marketParameters: <code>from</code> (example: <code>5</code>), <code>to</code> (example: <code>7</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>exact_number</code><ul>\n<li>description: Exact number of goals/sets: 0, 1, 2, 3, 4, 5, 6 and more</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=gte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>exact_number_team</code><ul>\n<li>description: Exact number of goals: Arsenal</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=gte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>exact_number_yes_no</code><ul>\n<li>description: Exact number of goals: yes/no</li>\n<li>marketParameters: <code>score</code> (example: <code>1</code>), <code>predicate</code> (example: <code>eq</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>exact_number_yes_no_team</code><ul>\n<li>description: Exact number of goals: yes/no Team</li>\n<li>marketParameters: <code>score</code> (example: <code>1</code>), <code>predicate</code> (example: <code>eq</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ht_ft</code><ul>\n<li>description: Half-time - full time score of the match: 1 / 1 - team1 won the 1st half &amp; match; X/X - draw in 1st half &amp; full time</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=htft, ht=draw, ft=draw</li>\n<li>kind=htft, ht=p1, ft=draw</li>\n<li>kind=htft, ht=p1, ft=p1</li>\n<li>kind=htft, ht=draw, ft=p1</li>\n<li>kind=htft, ht=p2, ft=p1</li>\n<li>kind=htft, ht=p1, ft=p2</li>\n<li>kind=htft, ht=p2, ft=draw</li>\n<li>kind=htft, ht=p2, ft=p2</li>\n<li>kind=htft, ht=draw, ft=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_yes_no</code><ul>\n<li>description: Both teams to score</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_and_win_team_yes_no</code><ul>\n<li>description: Both team to score in scope and team x win</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_score_in_both_halves_yes_no_team</code><ul>\n<li>description: Team score in first and second half</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_win_both_halves_yes_no_team</code><ul>\n<li>description: Team win both halves.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_win_either_half_yes_no_team</code><ul>\n<li>description: Team win first or second half.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_win_first_half_and_not_to_lose_yes_no_team</code><ul>\n<li>description: Team to win first half and win match or draw</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_win_by_exact_number_yes_no_team</code><ul>\n<li>description: Team to win when score x gte|lte|eq then score of other team and this team win the match.</li>\n<li>marketParameters: <code>score</code> (example: <code>1</code>), <code>predicate</code> (example: <code>eq</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_win_by_exact_number_or_draw_yes_no_team</code><ul>\n<li>description: Team to win when score x gte|lte|eq then score of other team and this team win the match. Or draw.</li>\n<li>marketParameters: <code>score</code> (example: <code>1</code>), <code>predicate</code> (example: <code>eq</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_to_score_yes_no_team</code><ul>\n<li>description: Team to score in a scope</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>draw</code><ul>\n<li>description: Score draw: yes / no</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>draw_yes_no</code><ul>\n<li>description: Will the match end in a draw: yes/no.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_and_o_yes_no</code><ul>\n<li>description: Both team to score and over</li>\n<li>marketParameters: <code>total</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_and_u_yes_no</code><ul>\n<li>description: Both team to score and under</li>\n<li>marketParameters: <code>total</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_first</code><ul>\n<li>description: Which team open score in scope.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=no</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_x</code><ul>\n<li>description: Which team to score x goal.</li>\n<li>marketParameters: <code>number</code> (example: <code>1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=no</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>before_goal_yes_no</code><ul>\n<li>description: Event will be before goal is scored : yes / no</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>before_corner_yes_no</code><ul>\n<li>description: Incident will be before corner</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>before_sub_yn</code><ul>\n<li>description: Incident will be before substitution</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_last</code><ul>\n<li>description: Which team score last goal.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=no</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_x_in_range</code><ul>\n<li>description: When will be scored x goal.</li>\n<li>marketParameters: <code>number</code> (example: <code>1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=range, from=10, to=15</li>\n<li>kind=range, from=16, to=20</li>\n<li>kind=range, from=21, to=30</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_in_range</code><ul>\n<li>description: When will be scored goal.</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>15</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_score_in_range_team</code><ul>\n<li>description: When will be scored goal by team</li>\n<li>marketParameters: <code>from</code> (example: <code>1</code>), <code>to</code> (example: <code>15</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>extra_inning_yes_no</code><ul>\n<li>description: Extra inning in baseball: yes/no</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>some_lose_first_set_and_win_match_yes_no</code><ul>\n<li>description: Some lose first set and win match</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_scopes_score</code><ul>\n<li>description: The highest scoring scopes. Sets 1&gt;2, 2&gt;1, 1=2</li>\n<li>marketParameters: <code>scope</code> (example: <code>set</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=multi_value, value1=1, value2=2, predicate=gt</li>\n<li>kind=multi_value, value1=1, value2=2, predicate=eq</li>\n<li>kind=multi_value, value1=2, value2=1, predicate=gt</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_scope_score</code><ul>\n<li>description: The highest scoring scope. Quarter 1, 2, 3, 4</li>\n<li>marketParameters: <code>scope</code> (example: <code>quarter</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=value, outcome=4, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>some_set_clean_win_in_match_yes_no</code><ul>\n<li>description: Some set will be won cleanly in the match. Tennis (6:0/0:6)</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_win_all_scopes_team_yes_no</code><ul>\n<li>description: Team win all scopes.</li>\n<li>marketParameters: <code>scope</code> (example: <code>quarter</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_win_first_quarter_and_match_yes_no_team</code><ul>\n<li>description: Team win first quarter and match.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>team_win_first_half_and_match_yes_no_team</code><ul>\n<li>description: Team win first half and match.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>win_first_half_n_not_win_ynt</code><ul>\n<li>description: Wins In First Half And Does Not Win A Match, {{teamName}}</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>overtime_yes_no</code><ul>\n<li>description: Will be overtime</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>runout_yes_no</code><ul>\n<li>description: Will be run-out in cricket match</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>review_var_yes_no</code><ul>\n<li>description: Will be video review VAR in soccer match</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_winner</code><ul>\n<li>description: Race winner</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n<li>kind=id, outcome=p3</li>\n<li>kind=id, outcome=p4</li>\n<li>kind=id, outcome=p5</li>\n<li>kind=id, outcome=p6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_place</code><ul>\n<li>description: Selected horse finishes in the first two</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n<li>kind=id, outcome=p3</li>\n<li>kind=id, outcome=p4</li>\n<li>kind=id, outcome=p5</li>\n<li>kind=id, outcome=p6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_show</code><ul>\n<li>description: Selected horse finishes in the first three</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n<li>kind=id, outcome=p3</li>\n<li>kind=id, outcome=p4</li>\n<li>kind=id, outcome=p5</li>\n<li>kind=id, outcome=p6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_forecast</code><ul>\n<li>description: Two selected horses must get to the finish first in specified order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2</li>\n<li>kind=id_sequence, outcome=p1,p3</li>\n<li>kind=id_sequence, outcome=p2,p3</li>\n<li>kind=id_sequence, outcome=p2,p1</li>\n<li>kind=id_sequence, outcome=p3,p2</li>\n<li>kind=id_sequence, outcome=p3,p1</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_reverse_forecast</code><ul>\n<li>description: Two selected horses must get to the finish first in any order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p3</li>\n<li>kind=id_sequence, outcome=p2,p3</li>\n<li>kind=id_sequence, outcome=p2,p1</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_tricast</code><ul>\n<li>description: Three selected horses must get to the finish first in specified order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2,p3</li>\n<li>kind=id_sequence, outcome=p1,p3,p2</li>\n<li>kind=id_sequence, outcome=p2,p3,p1</li>\n<li>kind=id_sequence, outcome=p2,p1,p3</li>\n<li>kind=id_sequence, outcome=p3,p2,p1</li>\n<li>kind=id_sequence, outcome=p3,p1,p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_reverse_tricast</code><ul>\n<li>description: Three selected horses must get to the finish first in any order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2,p3</li>\n<li>kind=id_sequence, outcome=p1,p2,p4</li>\n<li>kind=id_sequence, outcome=p1,p2,p5</li>\n<li>kind=id_sequence, outcome=p1,p2,p6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_quarter</code><ul>\n<li>description: Four selected horses must get to the finish first in specified order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2,p3,p4</li>\n<li>kind=id_sequence, outcome=p2,p1,p3,p4</li>\n<li>kind=id_sequence, outcome=p2,p1,p4,p3</li>\n<li>kind=id_sequence, outcome=p3,p1,p4,p2</li>\n<li>kind=id_sequence, outcome=p3,p1,p2,p4</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_swinger</code><ul>\n<li>description: Both your horses finish in the first three in any order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2</li>\n<li>kind=id_sequence, outcome=p1,p3</li>\n<li>kind=id_sequence, outcome=p2,p3</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_high_low</code><ul>\n<li>description: Race winner lane over/under (1,2,3|4,5,6). If participant number is odd then middle lane relates to over (1,2,3|4,5,6,7).</li>\n<li>marketParameters: <code>total</code> (example: <code>3.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=low</li>\n<li>kind=enum, outcome=high</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_odd_even</code><ul>\n<li>description: Race winner lane odd/even</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_odd_even_high_low</code><ul>\n<li>description: Combination of odd even and over under for racing</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd_low</li>\n<li>kind=enum, outcome=odd_high</li>\n<li>kind=enum, outcome=even_low</li>\n<li>kind=enum, outcome=even_high</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>race_pairs</code><ul>\n<li>description: Not supported yet</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>roulette_odd_even</code><ul>\n<li>description: Like a regular odd_even but if zero then loss</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>roulette_numbers</code><ul>\n<li>description: Roulette numbers</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value_sequence, outcome=32</li>\n<li>kind=value_sequence, outcome=25,17,34,6,27,13</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>roulette_red_black</code><ul>\n<li>description: Red or black</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=red</li>\n<li>kind=enum, outcome=black</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>racing_roulette_first</code><ul>\n<li>description: Race winner</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p13</li>\n<li>kind=id_sequence, outcome=p12</li>\n<li>kind=id_sequence, outcome=p1,p2,p3</li>\n<li>kind=id_sequence, outcome=p4,p5,p6</li>\n<li>kind=id_sequence, outcome=p7,p8,p9</li>\n<li>kind=id_sequence, outcome=p10,p11,p12</li>\n<li>kind=id_sequence, outcome=p1,p3,p5,p7,p9,p11</li>\n<li>kind=id_sequence, outcome=p2,p4,p6,p8,p10,p12</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>racing_roulette_first_second</code><ul>\n<li>description: First and second in order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence_double, first=p1, second=p2</li>\n<li>kind=id_sequence_double, first=p1,p2,p3, second=p4,p5,p6</li>\n<li>kind=id_sequence_double, first=p1,p3,p5,p7,p9,p11, second=p2,p4,p6,p8,p10,p12</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>racing_roulette_first_second_third</code><ul>\n<li>description: First, second and third in order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence_triple, first=p1, second=p2, third=p3</li>\n<li>kind=id_sequence_triple, first=p1,p2,p3, second=p4,p5,p6, third=p7,p8,p9</li>\n<li>kind=id_sequence_triple, first=p1,p3,p5,p7,p9,p11, second=p2,p4,p6,p8,p10,p12, third=p2,p4,p6,p8,p10,p12</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>racing_roulette_in_first_three</code><ul>\n<li>description: Finish if first three</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1</li>\n<li>kind=id_sequence, outcome=p2,p4</li>\n<li>kind=id_sequence, outcome=p1,p2,p4</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>racing_roulette_two_from_three</code><ul>\n<li>description: First three in order</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id_sequence, outcome=p1,p2,p3</li>\n<li>kind=id_sequence, outcome=p3,p2,p1</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>keno_subset_in_set</code><ul>\n<li>description: Keno</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value_sequence, outcome=32,15,19,4,21,2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>keno_heads_tails</code><ul>\n<li>description: Keno heads tails</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=heads</li>\n<li>kind=enum, outcome=evens</li>\n<li>kind=enum, outcome=tails</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_first_balls</code><ul>\n<li>description: Player chooses first n balls from m drawn</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value_sequence, outcome=8</li>\n<li>kind=value_sequence, outcome=1,2</li>\n<li>kind=value_sequence, outcome=1,2,3</li>\n<li>kind=value_sequence, outcome=1,2,3,4</li>\n<li>kind=value_sequence, outcome=1,2,3,4,5</li>\n<li>kind=value_sequence, outcome=1,2,3,4,5,6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_first_color</code><ul>\n<li>description: First color</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=green</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_colors_count</code><ul>\n<li>description: Drawn colors count</li>\n<li>marketParameters: <code>color</code> (example: <code>red</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=0, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=gte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_subset_in_set_strict</code><ul>\n<li>description: n Or More From 6</li>\n<li>marketParameters: <code>number</code> (example: <code>5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value_sequence, outcome=32,15,19,4,21,2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_sum_odd_even</code><ul>\n<li>description: Sum of draw odd or even</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lucky_loot_sum_high_low</code><ul>\n<li>description: Sum of draw higher than 75.5 or lower</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=low</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_win_toss</code><ul>\n<li>description: Market with 2 outcomes. 1st outcome: win home_team, 2nd win away_team</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_win_toss_and_match_yes_no_team</code><ul>\n<li>description: Team wins the coin toss and wins the match: yes/no.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>to_win_toss_and_score_first_ball_yes_no_team</code><ul>\n<li>description: Team wins the toss and scores off the first ball: yes/no.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_wicket_method</code><ul>\n<li>description: How the first wicket falls: caught, bowled, lbw, run-out, stumped, or other.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=caught</li>\n<li>kind=enum, outcome=bowled</li>\n<li>kind=enum, outcome=lbw</li>\n<li>kind=enum, outcome=runout</li>\n<li>kind=enum, outcome=stumped</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_wicket_method_2_way</code><ul>\n<li>description: First wicket method simplified: caught or other.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=caught</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_wicket_method_team</code><ul>\n<li>description: How the Nth wicket falls for a team: caught, bowled, lbw, run-out, stumped, or other.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>3</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=caught</li>\n<li>kind=enum, outcome=bowled</li>\n<li>kind=enum, outcome=lbw</li>\n<li>kind=enum, outcome=runout</li>\n<li>kind=enum, outcome=stumped</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_wicket_method_2_way_team</code><ul>\n<li>description: Nth wicket method for the team simplified: caught or other.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>3</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=caught</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>score_at_fall_of_x_wicket_ou</code><ul>\n<li>description: Total runs scored at the fall of the Nth wicket: over/under.</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>), <code>total</code> (example: <code>160</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>score_at_fall_of_x_wicket_ou_team</code><ul>\n<li>description: Team's runs at the fall of their Nth wicket: over/under.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>2</code>), <code>total</code> (example: <code>160</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>score_at_fall_of_x_wicket_odd_even_team</code><ul>\n<li>description: Team's runs at the fall of the Nth wicket: odd or even.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>2</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_wicket_golden_duck_yes_no_team</code><ul>\n<li>description: Nth wicket for the team is a golden duck (out on first ball): yes/no.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>), <code>number</code> (example: <code>3</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>odd_even_player</code><ul>\n<li><p>description:</p>\n<p>  Player's individual score is odd or even.\n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=odd</li>\n<li>kind=enum, outcome=even</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>player_out_method</code><ul>\n<li>description: How a specific player gets out: caught or other.</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=caught</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>player_bingo_yes</code><ul>\n<li>description: player_bingo_yes</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>player_bullseye_yes</code><ul>\n<li>description: player_bullseye_yes</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ou_player</code><ul>\n<li><p>description:</p>\n<p>  Player's individual score over/under a specified score type. \n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>oupt</code><ul>\n<li><p>description:</p>\n<p>  Player's individual score over/under a specified score type. \n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>0.5</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_ynpt</code><ul>\n<li><p>description:</p>\n<p>  Player on a specific team scores first: yes/no.\n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>last_ynpt</code><ul>\n<li><p>description:</p>\n<p>  Player on a specific team scores last: yes/no.\n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>assist_oupt</code><ul>\n<li><p>description:</p>\n<p>  Player's individual score by assists over/under. \n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>), <code>total</code> (example: <code>0.5</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>or_ast_ynpt</code><ul>\n<li><p>description:</p>\n<p>  Player on a specific team to score or assist: yes/no.\n  If the player is not present in the starting lineups, the pick must be settled as return. Players substituted in are not count and must be settled as return.</p>\n</li>\n<li><p>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>)</p>\n</li>\n<li><p>outcomeParameters:</p>\n<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>pre_live_ou_player</code><ul>\n<li>description: pre_live_ou_player</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_scored_player_yes_no</code><ul>\n<li>description: Player reaches X runs/points: yes/no.</li>\n<li>marketParameters: <code>score</code> (example: <code>100</code>), <code>player</code> (example: <code>peterparker</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>fifty_scored_player_and_team_win_yes</code><ul>\n<li>description: Player scores 50+ and their team wins: yes.</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_player_out_yes_no_team</code><ul>\n<li>description: Specific player from the team is out by the Nth wicket: yes/no.</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>), <code>player</code> (example: <code>peter_dendocker</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>top_player_team</code><ul>\n<li>description: Which player from a specific team scores the most.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=_name, name=peter_dendocker</li>\n<li>kind=_name, name=bob_benksy</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>top_player</code><ul>\n<li>description: Which player scores the most in the match.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=_name, name=peter_dendocker</li>\n<li>kind=_name, name=bob_benksy</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>matchbets</code><ul>\n<li>description: Head-to-head: which of two named players scores more.</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker__bob_benksy</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=_name, name=peter_dendocker</li>\n<li>kind=_name, name=bob_benksy</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_individual_score_yes_no</code><ul>\n<li>description: Any individual player reaches X runs/points: yes/no.</li>\n<li>marketParameters: <code>score</code> (example: <code>100</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_individual_score_yes_no_team</code><ul>\n<li>description: Any player from the team reaches X runs/points: yes/no.</li>\n<li>marketParameters: <code>score</code> (example: <code>100</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_individual_score_ou</code><ul>\n<li>description: Total highest_individual_score_ou.</li>\n<li>marketParameters: <code>total</code> (example: <code>3.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_opening_partnership</code><ul>\n<li>description: Market with 3 outcomes. 1st outcome: win home_team, 2nd draw, 3rd win away_team</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>opening_partnership_ou_team</code><ul>\n<li>description: Total opening_partnership_ou_team.</li>\n<li>marketParameters: <code>total</code> (example: <code>3.5</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_scored_partnership_yes</code><ul>\n<li>description: Named batting partnership reaches X runs: yes.</li>\n<li>marketParameters: <code>player</code> (example: <code>peter_dendocker__bob_benksy</code>), <code>number</code> (example: <code>25</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>incident_yes_no_team</code><ul>\n<li>description: Specified incident occurs for the team: yes/no.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_scored_yes_no_team</code><ul>\n<li>description: Team reaches X runs/points in the scope: yes/no.</li>\n<li>marketParameters: <code>score</code> (example: <code>100</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_scoring_team</code><ul>\n<li>description: How the first scoring play occurs for a team (e.g. 3-pointer, other).</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_boundary_team</code><ul>\n<li>description: Type of the Nth boundary for the team: four (s4) or six (s6).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=s4</li>\n<li>kind=enum, outcome=s6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>captain_fantastic_team_yes</code><ul>\n<li>description: captain_fantastic_team_yes</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>clean_sweep_team_yes</code><ul>\n<li>description: clean_sweep_team_yes</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_runscorer</code><ul>\n<li>description: Which team has the highest individual run scorer, or tie.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_wicket_taker</code><ul>\n<li>description: Which team has the highest individual wicket taker, or tie.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=id, outcome=p1</li>\n<li>kind=enum, outcome=draw</li>\n<li>kind=id, outcome=p2</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_o_yes_no</code><ul>\n<li>description: Both teams score at least X runs/points (over): yes/no.</li>\n<li>marketParameters: <code>total</code> (example: <code>160</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>both_to_score_u_yes_no</code><ul>\n<li>description: Both teams score under X runs/points: yes/no.</li>\n<li>marketParameters: <code>total</code> (example: <code>160</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>winning_over</code><ul>\n<li>description: In which over range the winning run is scored (cricket).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=range, from=10, to=20</li>\n<li>kind=value, outcome=20, predicate=eq</li>\n<li>kind=value, outcome=19, predicate=eq</li>\n<li>kind=value, outcome=19, predicate=lte</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_boundary</code><ul>\n<li>description: First boundary type: four (s4) or six (s6).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=s4</li>\n<li>kind=enum, outcome=s6</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>last_action</code><ul>\n<li>description: Type of the last delivery/action: single, four, six, wicket, or other (cricket).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=single</li>\n<li>kind=enum, outcome=s4</li>\n<li>kind=enum, outcome=s6</li>\n<li>kind=enum, outcome=wicket</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>scope_result</code><ul>\n<li>description: Scope result: specific score value or other.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>super_over_yes_no</code><ul>\n<li>description: Will there be a super over (cricket tiebreaker): yes/no.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>highest_over_ou</code><ul>\n<li>description: Highest-scoring over total over/under a specified line (cricket).</li>\n<li>marketParameters: <code>total</code> (example: <code>16.5</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ahead_of_time_yes_no</code><ul>\n<li>description: Ahead of time win</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>ahead_of_time_yes_no_team</code><ul>\n<li>description: Team to win ahead of time</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>by_point_yes_no_team</code><ul>\n<li>description: Win by points</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>win_round</code><ul>\n<li>description: In which round the fight is won.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=1, predicate=eq</li>\n<li>kind=value, outcome=2, predicate=eq</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>incident_yes_no</code><ul>\n<li>description: Some incident(wicket in cricket) to have place during the scope</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>lost_for_ou_team</code><ul>\n<li>description: Cricket market. Wicket lost for x runs for team</li>\n<li>marketParameters: <code>score</code> (example: <code>200</code>), <code>total</code> (example: <code>3.5</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>x_player_out_team</code><ul>\n<li>description: Which player from the team is out at the Nth wicket.</li>\n<li>marketParameters: <code>number</code> (example: <code>2</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=_name, name=peter_dendocker</li>\n<li>kind=_name, name=bob_benksy</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>first_scoring</code><ul>\n<li>description: Type of the first scoring play (e.g. exact value or other).</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=value, outcome=3, predicate=eq</li>\n<li>kind=enum, outcome=other</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>win_margin_ou_team</code><ul>\n<li>description: Team's winning margin over/under a specified line.</li>\n<li>marketParameters: <code>total</code> (example: <code>2.5</code>), <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=over</li>\n<li>kind=enum, outcome=under</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>kd_incident_yes_no</code><ul>\n<li>description: Will there be a knock-down in the match: yes/no.</li>\n<li>marketParameters: none</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n<li><code>kd_incident_yes_no_team</code><ul>\n<li>description: Team will knock the opponent down: yes/no.</li>\n<li>marketParameters: <code>team</code> (example: <code>p1</code>)</li>\n<li>outcomeParameters:<ul>\n<li>kind=enum, outcome=yes</li>\n<li>kind=enum, outcome=no</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"4fc4f1bf-536d-4a60-b8e2-91457dd07286"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"1c04e22b-9729-4544-a980-0e95d7eb3036"}}],"_postman_id":"82926e1c-fd81-43d2-989d-c165c3b99fdb"},{"name":"Sportsbook Tree","item":[{"name":"Sports","item":[],"id":"0756419a-d3e5-4a52-ac40-06fe8e74b0b3","description":"<h2 id=\"sports\">Sports</h2>\n<p>Known <code>sportId</code> → code mapping. <strong>New sports may be added over time. Integrators MUST NOT declare a closed enum / fixed set of UUIDs on their side; treat the field as an open string and handle unknown ids gracefully so the integration does not break when a new sport is introduced.</strong></p>\n<p>Same table applies to both Event Pick and Outright Pick <code>sportId</code> fields.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>sportId</th>\n<th>code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>decc47a0-43f8-4f15-b6a3-6beb9368c649</code></td>\n<td>decimal-cricket</td>\n</tr>\n<tr>\n<td><code>1da0f5f1-daf2-4c69-baf5-4ae2f266e5f4</code></td>\n<td>kiron-badminton</td>\n</tr>\n<tr>\n<td><code>cf0cb942-1ee0-4526-9b48-d4eb54a7720a</code></td>\n<td>kiron-archery</td>\n</tr>\n<tr>\n<td><code>d69396a4-cf1d-11e9-90ca-0242ac13000a</code></td>\n<td>canoe</td>\n</tr>\n<tr>\n<td><code>d691f9fc-cf1d-11e9-b13b-0242ac13000a</code></td>\n<td>athletics</td>\n</tr>\n<tr>\n<td><code>d6931db4-cf1d-11e9-af54-0242ac13000a</code></td>\n<td>rugby</td>\n</tr>\n<tr>\n<td><code>d6944ef0-cf1d-11e9-b474-0242ac13000a</code></td>\n<td>sepak-takraw</td>\n</tr>\n<tr>\n<td><code>d6929204-cf1d-11e9-aed5-0242ac13000a</code></td>\n<td>cricket</td>\n</tr>\n<tr>\n<td><code>6c7d15b9-1c79-4ba4-8a40-9b5e55c5a8da</code></td>\n<td>e-tennis</td>\n</tr>\n<tr>\n<td><code>d81efba4-608f-4b4e-be63-d93732f5cb96</code></td>\n<td>e-ice-hockey</td>\n</tr>\n<tr>\n<td><code>d692a4ec-cf1d-11e9-91b2-0242ac13000a</code></td>\n<td>cycling</td>\n</tr>\n<tr>\n<td><code>d693aac2-cf1d-11e9-89ff-0242ac13000a</code></td>\n<td>equestrian</td>\n</tr>\n<tr>\n<td><code>f07966d8-1922-467d-96fb-727929358052</code></td>\n<td>curling</td>\n</tr>\n<tr>\n<td><code>d69430be-cf1d-11e9-85f7-0242ac13000a</code></td>\n<td>rallying</td>\n</tr>\n<tr>\n<td><code>d69267de-cf1d-11e9-b8ad-0242ac13000a</code></td>\n<td>beach-volleyball</td>\n</tr>\n<tr>\n<td><code>fb6d3b06-0c0d-4a9e-b612-2c41bf08807f</code></td>\n<td>e-basketball</td>\n</tr>\n<tr>\n<td><code>d15083fa-81ac-4395-be69-54ff56a3ef59</code></td>\n<td>overwatch</td>\n</tr>\n<tr>\n<td><code>d69477e0-cf1d-11e9-8a21-0242ac13000a</code></td>\n<td>surfing</td>\n</tr>\n<tr>\n<td><code>4e8d5ce3-97e2-4035-a4ed-3b81eab2c31b</code></td>\n<td>e-volleyball</td>\n</tr>\n<tr>\n<td><code>4dc3ac2f-c8ab-4aef-a369-6700a72ea63d</code></td>\n<td>lol</td>\n</tr>\n<tr>\n<td><code>d69426b4-cf1d-11e9-85be-0242ac13000a</code></td>\n<td>racketlon</td>\n</tr>\n<tr>\n<td><code>5da5ed87-b43e-4918-be12-e567a02028ca</code></td>\n<td>kiron-keno</td>\n</tr>\n<tr>\n<td><code>c0bd7cd7-2f15-4e10-bbec-fd699be5d296</code></td>\n<td>kiron-harness-racing</td>\n</tr>\n<tr>\n<td><code>8e0f34e5-7b4f-4319-9288-2a568259c668</code></td>\n<td>kiron-cricket</td>\n</tr>\n<tr>\n<td><code>27d667e3-8260-4afb-9ee3-d520c825940d</code></td>\n<td>kiron-racing-roulette</td>\n</tr>\n<tr>\n<td><code>d6922ab2-cf1d-11e9-9ad4-0242ac13000a</code></td>\n<td>badminton</td>\n</tr>\n<tr>\n<td><code>d693df60-cf1d-11e9-9269-0242ac13000a</code></td>\n<td>hurling</td>\n</tr>\n<tr>\n<td><code>d69481ea-cf1d-11e9-80a0-0242ac13000a</code></td>\n<td>triathlon</td>\n</tr>\n<tr>\n<td><code>d6936e72-cf1d-11e9-bfab-0242ac13000a</code></td>\n<td>volleyball</td>\n</tr>\n<tr>\n<td><code>d693b5bc-cf1d-11e9-9d1e-0242ac13000a</code></td>\n<td>fencing</td>\n</tr>\n<tr>\n<td><code>d691ecc8-cf1d-11e9-a78c-0242ac13000a</code></td>\n<td>american-football</td>\n</tr>\n<tr>\n<td><code>ac3afc6b-4cc5-44f7-9742-5722942bd651</code></td>\n<td>rainbow6</td>\n</tr>\n<tr>\n<td><code>5b926879-bb7d-4c28-b0bd-742107ec02ba</code></td>\n<td>hearthstone</td>\n</tr>\n<tr>\n<td><code>d6938c90-cf1d-11e9-b350-0242ac13000a</code></td>\n<td>bowls</td>\n</tr>\n<tr>\n<td><code>27cbd9ad-fd35-420d-9ccd-ea2c04eb50cf</code></td>\n<td>warcraft3</td>\n</tr>\n<tr>\n<td><code>d6946dd6-cf1d-11e9-a550-0242ac13000a</code></td>\n<td>speedway</td>\n</tr>\n<tr>\n<td><code>d693fe32-cf1d-11e9-9774-0242ac13000a</code></td>\n<td>kayak</td>\n</tr>\n<tr>\n<td><code>d693cab6-cf1d-11e9-8f30-0242ac13000a</code></td>\n<td>gaelic-football</td>\n</tr>\n<tr>\n<td><code>d6945936-cf1d-11e9-9307-0242ac13000a</code></td>\n<td>shooting</td>\n</tr>\n<tr>\n<td><code>4be04662-eba6-4a45-8ff9-4866869215da</code></td>\n<td>rocket-league</td>\n</tr>\n<tr>\n<td><code>43f82846-eed2-485b-87b6-bfc8de5b9854</code></td>\n<td>kiron-motor-racing</td>\n</tr>\n<tr>\n<td><code>14282c50-32ea-4ae5-aecf-15b907ce751e</code></td>\n<td>kiron-steeple-chase</td>\n</tr>\n<tr>\n<td><code>520ab8f7-87b4-41bd-b004-3667e46d1789</code></td>\n<td>kiron-ice-hockey</td>\n</tr>\n<tr>\n<td><code>d3c5e46d-072c-404c-af61-30e5418023af</code></td>\n<td>kiron-lucky-loot</td>\n</tr>\n<tr>\n<td><code>bbe839ec-3e55-4746-9de4-56bf367dd3c9</code></td>\n<td>starcraft2</td>\n</tr>\n<tr>\n<td><code>444481ae-9bea-4a5f-9b6c-4a4feb424444</code></td>\n<td>politics</td>\n</tr>\n<tr>\n<td><code>d692af28-cf1d-11e9-9790-0242ac13000a</code></td>\n<td>darts</td>\n</tr>\n<tr>\n<td><code>2009e404-f67f-11e9-a05a-f01898ec59ee</code></td>\n<td>esports</td>\n</tr>\n<tr>\n<td><code>d69444dc-cf1d-11e9-9192-0242ac13000a</code></td>\n<td>sailing</td>\n</tr>\n<tr>\n<td><code>d692e16e-cf1d-11e9-bfdf-0242ac13000a</code></td>\n<td>golf</td>\n</tr>\n<tr>\n<td><code>d69463a4-cf1d-11e9-b57b-0242ac13000a</code></td>\n<td>softball</td>\n</tr>\n<tr>\n<td><code>87f9bcca-56b8-4d5f-a73a-7fd3988a7647</code></td>\n<td>unknown</td>\n</tr>\n<tr>\n<td><code>d6934640-cf1d-11e9-864b-0242ac13000a</code></td>\n<td>soccer</td>\n</tr>\n<tr>\n<td><code>d6941296-cf1d-11e9-9be5-0242ac13000a</code></td>\n<td>pelota</td>\n</tr>\n<tr>\n<td><code>d6933c2c-cf1d-11e9-9e86-0242ac13000a</code></td>\n<td>snooker</td>\n</tr>\n<tr>\n<td><code>d69309a0-cf1d-11e9-bfa6-0242ac13000a</code></td>\n<td>motorcycling</td>\n</tr>\n<tr>\n<td><code>d693a0b8-cf1d-11e9-8886-0242ac13000a</code></td>\n<td>diving</td>\n</tr>\n<tr>\n<td><code>9f4b280e-d19d-43df-bfaa-ff500b221294</code></td>\n<td>e-soccer</td>\n</tr>\n<tr>\n<td><code>d693d4e8-cf1d-11e9-b511-0242ac13000a</code></td>\n<td>greyhounds-racing</td>\n</tr>\n<tr>\n<td><code>d6925dc0-cf1d-11e9-b60e-0242ac13000a</code></td>\n<td>beach-soccer</td>\n</tr>\n<tr>\n<td><code>e1e78fb9-0e4e-4f70-9f56-f2495516e513</code></td>\n<td>kiron-table-tennis</td>\n</tr>\n<tr>\n<td><code>befda60a-c8d7-4dc4-94e9-23ad059d164c</code></td>\n<td>kiron-hounds-racing</td>\n</tr>\n<tr>\n<td><code>4a8f699c-296e-4ff0-8aeb-a3f67c1bb91f</code></td>\n<td>kiron-roulette</td>\n</tr>\n<tr>\n<td><code>d69239b2-cf1d-11e9-90e6-0242ac13000a</code></td>\n<td>bandy</td>\n</tr>\n<tr>\n<td><code>d6928606-cf1d-11e9-878b-0242ac13000a</code></td>\n<td>chess</td>\n</tr>\n<tr>\n<td><code>d693787c-cf1d-11e9-9c02-0242ac13000a</code></td>\n<td>water-polo</td>\n</tr>\n<tr>\n<td><code>d6921df6-cf1d-11e9-8d12-0242ac13000a</code></td>\n<td>auto-racing</td>\n</tr>\n<tr>\n<td><code>d6929b82-cf1d-11e9-a89e-0242ac13000a</code></td>\n<td>cross-country-skiing</td>\n</tr>\n<tr>\n<td><code>d69250c8-cf1d-11e9-b1d7-0242ac13000a</code></td>\n<td>basketball</td>\n</tr>\n<tr>\n<td><code>d6948c08-cf1d-11e9-880f-0242ac13000a</code></td>\n<td>trotting</td>\n</tr>\n<tr>\n<td><code>d692eb78-cf1d-11e9-b183-0242ac13000a</code></td>\n<td>handball</td>\n</tr>\n<tr>\n<td><code>d6949612-cf1d-11e9-a369-0242ac13000a</code></td>\n<td>yachting</td>\n</tr>\n<tr>\n<td><code>d6943ad2-cf1d-11e9-b058-0242ac13000a</code></td>\n<td>rowing</td>\n</tr>\n<tr>\n<td><code>d6935a54-cf1d-11e9-978e-0242ac13000a</code></td>\n<td>table-tennis</td>\n</tr>\n<tr>\n<td><code>d693ea0a-cf1d-11e9-af98-0242ac13000a</code></td>\n<td>indycar-racing</td>\n</tr>\n<tr>\n<td><code>d692f582-cf1d-11e9-a815-0242ac13000a</code></td>\n<td>ice-hockey</td>\n</tr>\n<tr>\n<td><code>60b9e9c2-8952-4663-8cc1-121c6828b61e</code></td>\n<td>kiron-soccer</td>\n</tr>\n<tr>\n<td><code>8db46e9b-b252-423b-a07f-b8379c9799eb</code></td>\n<td>csgo</td>\n</tr>\n<tr>\n<td><code>52f52608-f67f-11e9-9a01-f01898ec59ee</code></td>\n<td>horse-racing</td>\n</tr>\n<tr>\n<td><code>d69313aa-cf1d-11e9-adb0-0242ac13000a</code></td>\n<td>netball</td>\n</tr>\n<tr>\n<td><code>200a0d94-f67f-11e9-a10f-f01898ec59ee</code></td>\n<td>winter-sports</td>\n</tr>\n<tr>\n<td><code>d693504a-cf1d-11e9-b002-0242ac13000a</code></td>\n<td>squash</td>\n</tr>\n<tr>\n<td><code>d6924664-cf1d-11e9-848a-0242ac13000a</code></td>\n<td>baseball</td>\n</tr>\n<tr>\n<td><code>82c462f6-5e53-4b43-ae41-c53865311439</code></td>\n<td>starcraft</td>\n</tr>\n<tr>\n<td><code>d69204f6-cf1d-11e9-9123-0242ac13000a</code></td>\n<td>aussie-rules</td>\n</tr>\n<tr>\n<td><code>d69271f2-cf1d-11e9-84d6-0242ac13000a</code></td>\n<td>biathlon</td>\n</tr>\n<tr>\n<td><code>d692ff96-cf1d-11e9-a3f3-0242ac13000a</code></td>\n<td>mma</td>\n</tr>\n<tr>\n<td><code>d693645e-cf1d-11e9-82b4-0242ac13000a</code></td>\n<td>tennis</td>\n</tr>\n<tr>\n<td><code>29d699ca-38ef-4ec6-8ddd-08a890ec13ba</code></td>\n<td>kiron-horse-racing</td>\n</tr>\n<tr>\n<td><code>2b39989c-5f4e-476d-8365-4fe5ec4e256c</code></td>\n<td>valorant</td>\n</tr>\n<tr>\n<td><code>d6941ca0-cf1d-11e9-a9a1-0242ac13000a</code></td>\n<td>pesapallo</td>\n</tr>\n<tr>\n<td><code>d6938286-cf1d-11e9-9e37-0242ac13000a</code></td>\n<td>wrestling</td>\n</tr>\n<tr>\n<td><code>52f52572-f67f-11e9-9a01-f01898ec59ee</code></td>\n<td>motorsport</td>\n</tr>\n<tr>\n<td><code>d692cd5a-cf1d-11e9-b9d7-0242ac13000a</code></td>\n<td>formula-1</td>\n</tr>\n<tr>\n<td><code>d6940882-cf1d-11e9-9415-0242ac13000a</code></td>\n<td>lotto</td>\n</tr>\n<tr>\n<td><code>4a2c3ff7-cf0c-4438-bc3a-01ab75b6d4ec</code></td>\n<td>dota2</td>\n</tr>\n<tr>\n<td><code>d691b7ee-cf1d-11e9-a00f-0242ac13000a</code></td>\n<td>alpine-skiing</td>\n</tr>\n<tr>\n<td><code>d692c346-cf1d-11e9-b5fb-0242ac13000a</code></td>\n<td>floorball</td>\n</tr>\n<tr>\n<td><code>d6933222-cf1d-11e9-890c-0242ac13000a</code></td>\n<td>ski-jumping</td>\n</tr>\n<tr>\n<td><code>d692b93c-cf1d-11e9-a996-0242ac13000a</code></td>\n<td>field-hockey</td>\n</tr>\n<tr>\n<td><code>d693c048-cf1d-11e9-8032-0242ac13000a</code></td>\n<td>fishing</td>\n</tr>\n<tr>\n<td><code>d6927b52-cf1d-11e9-a4a2-0242ac13000a</code></td>\n<td>boxing</td>\n</tr>\n<tr>\n<td><code>d692d764-cf1d-11e9-90f1-0242ac13000a</code></td>\n<td>futsal</td>\n</tr>\n<tr>\n<td><code>d693f428-cf1d-11e9-a2d1-0242ac13000a</code></td>\n<td>kabaddi</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"7d9a542c-0a5e-425c-8248-5b69540f9f28"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"05c56e29-0653-492a-9ad3-d51c6697e350"}}],"_postman_id":"0756419a-d3e5-4a52-ac40-06fe8e74b0b3"},{"name":"Pagination","item":[],"id":"07a5c9c7-4731-43c7-beb1-bb203a92f7f8","description":"<h2 id=\"pagination\">Pagination</h2>\n<p>All sportsbook list endpoints (<code>Find Categories</code>, <code>Find Tournaments</code>, <code>Find Events</code>) share the same cursor-based pagination scheme. The request body accepts three optional objects: <code>cursor</code>, <code>where</code>, <code>order</code>. All three are independent and can be combined.</p>\n<hr />\n<h4 id=\"cursor-object-optional\"><code>cursor</code> (object, optional)</h4>\n<p>Relay-style cursor pagination. Pick one direction per call: forward (<code>first</code> + optional <code>after</code>) or backward (<code>last</code> + optional <code>before</code>). If <code>cursor</code> is omitted entirely a server-side default page size is used.</p>\n<ul>\n<li><p><code>first</code> (int, optional) - Page size when paging forward. Take the first <code>N</code> items after <code>after</code>.</p>\n</li>\n<li><p><code>after</code> (string, optional) - Opaque cursor returned by a previous response (<code>pageInfo.endCursor</code>). Page starts strictly after this position. Omit for the first page.</p>\n</li>\n<li><p><code>last</code> (int, optional) - Page size when paging backward. Take the last <code>N</code> items before <code>before</code>.</p>\n</li>\n<li><p><code>before</code> (string, optional) - Opaque cursor returned by a previous response (<code>pageInfo.startCursor</code>). Page ends strictly before this position.</p>\n</li>\n</ul>\n<p><strong>Rules:</strong></p>\n<ul>\n<li>Use <code>first</code>/<code>after</code> together for forward paging, <code>last</code>/<code>before</code> together for backward paging. Do not mix forward and backward fields in a single request.</li>\n<li>Cursors are opaque base64 tokens. They are not parseable identifiers - do not construct them on the client side; always echo back what the server returned.</li>\n<li>Cursors are stable across the same <code>where</code> + <code>order</code> combination. If you change filtering or sorting between calls, start the iteration from scratch (omit <code>after</code>/<code>before</code>).</li>\n</ul>\n<hr />\n<h4 id=\"where-object-optional\"><code>where</code> (object, optional)</h4>\n<p>Generic predicate tree used to filter the result set. A <code>where</code> node is either a <strong>leaf</strong> (a single condition on one field) or a <strong>branch</strong> (a logical combination of nested nodes).</p>\n<p>Object:</p>\n<ul>\n<li><p><code>predicate</code> (enum, required) - The operator applied at this node. See predicate list below.</p>\n</li>\n<li><p><code>fieldPath</code> (string, leaf only) - Name of the field this leaf filters on. Allowed values are listed per endpoint under <code>whereFieldPaths</code> in the request description.</p>\n</li>\n<li><p><code>value</code> (string, leaf only) - Right-hand side value of the predicate, serialised as a string. For <code>in</code> / <code>not_in</code> pass a comma-separated list (e.g. <code>\"uuid1,uuid2\"</code>). For timestamps pass <strong>epoch milliseconds as a string</strong> (e.g. <code>\"1779753600000\"</code> for <code>2026-05-26T00:00:00Z</code>) or a relative date token (see <strong>Timestamp values</strong> below). ISO-8601 strings are NOT accepted.</p>\n</li>\n<li><p><code>operands</code> (array, branch only) - Nested <code>where</code> nodes combined by the branch <code>predicate</code> (<code>and</code> / <code>or</code>). Branch nodes must not set <code>fieldPath</code> or <code>value</code>.</p>\n</li>\n</ul>\n<p><strong>Predicates:</strong></p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>predicate</th>\n<th>shape</th>\n<th>meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>and</code></td>\n<td>branch</td>\n<td>All operands must match</td>\n</tr>\n<tr>\n<td><code>or</code></td>\n<td>branch</td>\n<td>At least one operand must match</td>\n</tr>\n<tr>\n<td><code>eq</code></td>\n<td>leaf</td>\n<td><code>fieldPath</code> equals <code>value</code></td>\n</tr>\n<tr>\n<td><code>not_eq</code></td>\n<td>leaf</td>\n<td><code>fieldPath</code> differs from <code>value</code></td>\n</tr>\n<tr>\n<td><code>in</code></td>\n<td>leaf</td>\n<td><code>fieldPath</code> is in the comma-separated list <code>value</code></td>\n</tr>\n<tr>\n<td><code>not_in</code></td>\n<td>leaf</td>\n<td><code>fieldPath</code> is not in the comma-separated list <code>value</code></td>\n</tr>\n<tr>\n<td><code>gt</code> / <code>gte</code> / <code>lt</code> / <code>lte</code></td>\n<td>leaf</td>\n<td>Numeric/temporal comparisons</td>\n</tr>\n<tr>\n<td><code>like</code> / <code>starts_with</code> / <code>ends_with</code></td>\n<td>leaf</td>\n<td>String matching (SQL <code>LIKE</code>-style)</td>\n</tr>\n<tr>\n<td><code>unaccent_like</code> / <code>unaccent_eq</code> / <code>unaccent_starts_with</code> / <code>unaccent_ends_with</code></td>\n<td>leaf</td>\n<td>Accent-insensitive variants</td>\n</tr>\n<tr>\n<td><code>is_null</code> / <code>is_not_null</code></td>\n<td>leaf</td>\n<td>Nullability check (omit <code>value</code>)</td>\n</tr>\n<tr>\n<td><code>is_true</code> / <code>is_false</code></td>\n<td>leaf</td>\n<td>Boolean check (omit <code>value</code>)</td>\n</tr>\n<tr>\n<td><code>is_empty</code> / <code>is_not_empty</code></td>\n<td>leaf</td>\n<td>Collection / string emptiness</td>\n</tr>\n<tr>\n<td><code>contains</code> / <code>contained_by</code> / <code>contains_key</code></td>\n<td>leaf</td>\n<td>JSON/array containment</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Timestamp values:</strong></p>\n<p>Timestamp <code>where</code> values are parsed by <code>parseDate</code>:</p>\n<ul>\n<li><strong>Epoch milliseconds</strong> (string): <code>\"1779753600000\"</code>. Recommended for absolute time bounds.</li>\n<li><strong>Relative period</strong>: ISO-8601 period prefixed with <code>P</code> (future) or <code>-P</code> (past), relative to <em>now</em>. Examples: <code>\"P1D\"</code> = +1 day, <code>\"-P1H\"</code> = -1 hour, <code>\"P7D\"</code> = +7 days.</li>\n<li><strong>Calendar modifier</strong>: <code>MD</code> = start of current day (UTC), <code>MW</code> = start of current week (Sunday), <code>MM</code> = start of current month, <code>MY</code> = start of current year. Example: <code>\"MD\"</code>.</li>\n<li><strong>Combined</strong>: <code>&lt;period&gt;_&lt;modifier&gt;</code> — apply period offset to the modifier anchor. Example: <code>\"P1D_MD\"</code> = start of tomorrow.</li>\n<li><strong>Time zone</strong> (optional suffix): append <code>_TZ&lt;zoneId&gt;</code>. Example: <code>\"MD_TZEurope/Berlin\"</code> = start of today in Berlin time.</li>\n</ul>\n<p>ISO-8601 instant strings like <code>\"2026-05-26T00:00:00Z\"</code> are <strong>not</strong> accepted and will fail with <code>Duration '&lt;value&gt;' not parsed.</code></p>\n<hr />\n<p><strong>Example - simple leaf:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"predicate\": \"eq\",\n  \"fieldPath\": \"category__sportId\",\n  \"value\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n}\n</code></pre>\n<p><strong>Example - composite (events starting in a time window and not finished):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"predicate\": \"and\",\n  \"operands\": [\n    { \"predicate\": \"gte\", \"fieldPath\": \"event__startTime\", \"value\": \"1779753600000\" },\n    { \"predicate\": \"lt\",  \"fieldPath\": \"event__startTime\", \"value\": \"1779840000000\" },\n    { \"predicate\": \"is_null\", \"fieldPath\": \"event__finishedAt\" }\n  ]\n}\n</code></pre>\n<hr />\n<h4 id=\"order-array-optional\"><code>order</code> (array, optional)</h4>\n<p>Ordered list of sort keys applied left-to-right. Each entry:</p>\n<ul>\n<li><p><code>fieldPath</code> (string, required) - One of the allowed <code>orderByFieldPaths</code> listed per endpoint.</p>\n</li>\n<li><p><code>direction</code> (enum, optional) - <code>ASC</code> (default) or <code>DESC</code>.</p>\n</li>\n</ul>\n<p>If <code>order</code> is omitted the endpoint applies its default sort (see each endpoint description).</p>\n<p><strong>Example:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">[\n  { \"fieldPath\": \"event__startTime\", \"direction\": \"ASC\" },\n  { \"fieldPath\": \"event__id\",        \"direction\": \"ASC\" }\n]\n</code></pre>\n<hr />\n<h4 id=\"page-response-object\"><code>page</code> (response object)</h4>\n<p>Every sportsbook list endpoint returns a <code>Page&lt;T&gt;</code> envelope under a domain-specific key (<code>categories</code>, <code>tournaments</code>, <code>events</code>).</p>\n<p>Object:</p>\n<ul>\n<li><p><code>edges</code> (array, required) - Items of the current page.</p>\n<ul>\n<li><code>cursor</code> (string, required) - Opaque cursor pointing at this specific edge. Pass it back as <code>after</code> / <code>before</code> to anchor subsequent calls at this position.</li>\n<li><code>node</code> (object, required) - The actual entity. Shape depends on the endpoint (<code>Category</code>, <code>Tournament</code>, <code>Event</code>).</li>\n</ul>\n</li>\n<li><p><code>pageInfo</code> (object, required) - Navigation metadata for the current slice.</p>\n<ul>\n<li><code>hasPreviousPage</code> (boolean, required) - True if a page exists before this slice.</li>\n<li><code>hasNextPage</code> (boolean, required) - True if a page exists after this slice.</li>\n<li><code>startCursor</code> (string, optional) - Cursor of the first edge; null when <code>edges</code> is empty.</li>\n<li><code>endCursor</code> (string, optional) - Cursor of the last edge; null when <code>edges</code> is empty.</li>\n<li><code>total</code> (long, required) - Total number of items matching <code>where</code> across all pages. <code>0</code> if totals are not requested / not available.</li>\n</ul>\n</li>\n</ul>\n<p><strong>Example response envelope:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"categories\": {\n    \"edges\": [\n      {\n        \"cursor\": \"eyJpZCI6IjExMTExMTExLTExMTEtMTExMS0xMTExLTExMTExMTExMTExMSJ9\",\n        \"node\": {\n          \"categoryId\": \"11111111-1111-1111-1111-111111111111\",\n          \"categoryName\": \"International Clubs\",\n          \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n        }\n      }\n    ],\n    \"pageInfo\": {\n      \"hasPreviousPage\": false,\n      \"hasNextPage\": true,\n      \"startCursor\": \"eyJpZCI6IjExMTExMTExLTExMTEtMTExMS0xMTExLTExMTExMTExMTExMSJ9\",\n      \"endCursor\": \"eyJpZCI6IjExMTExMTExLTExMTEtMTExMS0xMTExLTExMTExMTExMTExMSJ9\",\n      \"total\": 42\n    }\n  }\n}\n</code></pre>\n<hr />\n<h4 id=\"iterating-forward\">Iterating forward</h4>\n<ol>\n<li>Issue the first call with <code>cursor</code> omitted (or <code>{\"first\": 50}</code>), plus your <code>where</code> / <code>order</code>.</li>\n<li>Read <code>pageInfo.hasNextPage</code>. If <code>true</code>, take <code>pageInfo.endCursor</code> and resend the same <code>where</code> / <code>order</code> with <code>cursor = { \"first\": 50, \"after\": &lt;endCursor&gt; }</code>.</li>\n<li>Repeat until <code>hasNextPage</code> is <code>false</code>.</li>\n</ol>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"928ae063-6e52-4968-b38b-972f03f39928"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"c2a2b22f-9e61-43f3-b5a0-b3a94c483dd1"}}],"_postman_id":"07a5c9c7-4731-43c7-beb1-bb203a92f7f8"},{"name":"Find Categories","id":"0e3b9c20-6aa3-4459-9452-b48797de7e4b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": {\n        \"first\": 50,\n        \"after\": null\n    },\n    \"where\": {\n        \"predicate\": \"eq\",\n        \"fieldPath\": \"category__sportId\",\n        \"value\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n    },\n    \"order\": [\n        { \"fieldPath\": \"category__priority\", \"direction\": \"ASC\" },\n        { \"fieldPath\": \"category__name\",     \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/categories","description":"<p>Returns a page of sportsbook categories for the given brand.</p>\n<p>Uses the shared cursor-based pagination described in the <strong>Pagination</strong> section of this folder (request fields: <code>cursor</code>, <code>where</code>, <code>order</code>; response envelope: <code>page</code>).</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider.</p>\n</li>\n<li><p><code>brand</code> (string, optional) - Brand code, when applicable.</p>\n</li>\n<li><p><code>cursor</code> (object, optional) - Pagination cursor. See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>where</code> (object, optional) - Filter tree over <code>whereFieldPaths</code> (see below). See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>order</code> (array, optional) - Sort over <code>orderByFieldPaths</code> (see below). Default: <code>category__name ASC, category__id ASC</code>.</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"wherefieldpaths\"><code>whereFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>category__id</code></td>\n<td>UUID</td>\n<td>Category id.</td>\n</tr>\n<tr>\n<td><code>category__name</code></td>\n<td>string</td>\n<td>Category name.</td>\n</tr>\n<tr>\n<td><code>category__sportId</code></td>\n<td>UUID</td>\n<td>Parent sport id. See <strong>Sports</strong> for the id → code mapping.</td>\n</tr>\n<tr>\n<td><code>category__eventStartTime</code></td>\n<td>timestamp</td>\n<td>Filters categories that have at least one event whose <code>startTime</code> matches the leaf condition. Value is <strong>epoch milliseconds as a string</strong> (or relative date token, see <strong>Pagination → Timestamp values</strong>). Useful with <code>gte</code> / <code>lt</code> to fetch categories that have upcoming events in a window.</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"orderbyfieldpaths\"><code>orderByFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>category__name</code></td>\n<td>string</td>\n<td>Case-insensitive. Default key.</td>\n</tr>\n<tr>\n<td><code>category__id</code></td>\n<td>UUID</td>\n<td>Stable tie-breaker. Default key.</td>\n</tr>\n<tr>\n<td><code>category__priority</code></td>\n<td>int</td>\n<td>Editorial sort priority (lower = higher up).</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>categories</code> (object, required) - <code>Page&lt;Category&gt;</code> envelope (see <strong>Pagination → <code>page</code></strong>).</li>\n</ul>\n<p>Category (<code>categories.edges[].node</code>):</p>\n<ul>\n<li><p><code>categoryId</code> (string, required) - Category id (UUID).</p>\n</li>\n<li><p><code>categoryName</code> (string, required) - Category display name.</p>\n</li>\n<li><p><code>sportId</code> (string, required) - Parent sport id (UUID). See <strong>Sports</strong>.</p>\n</li>\n</ul>\n","auth":{"type":"noauth","isInherited":true,"source":{"_postman_id":"a104990e-b123-43bf-9db7-f03dbb389c4c","id":"a104990e-b123-43bf-9db7-f03dbb389c4c","name":"Sportsbook Tree","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","sportsbook","categories"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"5bd5645d-f628-459d-b01b-2c7f2c110323","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": { \"first\": 2 },\n    \"where\": {\n        \"predicate\": \"eq\",\n        \"fieldPath\": \"category__sportId\",\n        \"value\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n    },\n    \"order\": [\n        { \"fieldPath\": \"category__priority\", \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/categories"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"categories\": {\n        \"edges\": [\n            {\n                \"cursor\": \"eyJpZCI6IjIyMjIyMjIyLTIyMjItMjIyMi0yMjIyLTIyMjIyMjIyMjIyMiJ9\",\n                \"node\": {\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n                    \"categoryName\": \"International Clubs\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            },\n            {\n                \"cursor\": \"eyJpZCI6IjIyMjIyMjIyLTIyMjItMjIyMi0yMjIyLTIyMjIyMjIyMjIyMyJ9\",\n                \"node\": {\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222223\",\n                    \"categoryName\": \"England\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            }\n        ],\n        \"pageInfo\": {\n            \"hasPreviousPage\": false,\n            \"hasNextPage\": true,\n            \"startCursor\": \"eyJpZCI6IjIyMjIyMjIyLTIyMjItMjIyMi0yMjIyLTIyMjIyMjIyMjIyMiJ9\",\n            \"endCursor\": \"eyJpZCI6IjIyMjIyMjIyLTIyMjItMjIyMi0yMjIyLTIyMjIyMjIyMjIyMyJ9\",\n            \"total\": 57\n        }\n    }\n}"}],"_postman_id":"0e3b9c20-6aa3-4459-9452-b48797de7e4b"},{"name":"Find Tournaments","id":"275ca586-1d21-4790-91c0-3ea142269a5a","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": {\n        \"first\": 50,\n        \"after\": null\n    },\n    \"where\": {\n        \"predicate\": \"eq\",\n        \"fieldPath\": \"tournament__categoryId\",\n        \"value\": \"22222222-2222-2222-2222-222222222222\"\n    },\n    \"order\": [\n        { \"fieldPath\": \"tournament__priority\", \"direction\": \"ASC\" },\n        { \"fieldPath\": \"tournament__name\",     \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/tournaments","description":"<p>Returns a page of sportsbook tournaments for the given brand.</p>\n<p>Uses the shared cursor-based pagination described in the <strong>Pagination</strong> section of this folder (request fields: <code>cursor</code>, <code>where</code>, <code>order</code>; response envelope: <code>page</code>).</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider.</p>\n</li>\n<li><p><code>brand</code> (string, optional) - Brand code, when applicable.</p>\n</li>\n<li><p><code>cursor</code> (object, optional) - Pagination cursor. See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>where</code> (object, optional) - Filter tree over <code>whereFieldPaths</code> (see below). See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>order</code> (array, optional) - Sort over <code>orderByFieldPaths</code> (see below). Default: <code>tournament__name ASC, tournament__id ASC</code>.</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"wherefieldpaths\"><code>whereFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>tournament__id</code></td>\n<td>UUID</td>\n<td>Tournament id.</td>\n</tr>\n<tr>\n<td><code>tournament__name</code></td>\n<td>string</td>\n<td>Tournament name.</td>\n</tr>\n<tr>\n<td><code>tournament__sportId</code></td>\n<td>UUID</td>\n<td>Parent sport id. See <strong>Sports</strong>.</td>\n</tr>\n<tr>\n<td><code>tournament__categoryId</code></td>\n<td>UUID</td>\n<td>Parent category id.</td>\n</tr>\n<tr>\n<td><code>tournament__eventStartTime</code></td>\n<td>timestamp</td>\n<td>Filters tournaments that have at least one event whose <code>startTime</code> matches the leaf condition. Value is <strong>epoch milliseconds as a string</strong> (or relative date token, see <strong>Pagination → Timestamp values</strong>). Useful with <code>gte</code> / <code>lt</code> to fetch tournaments that have upcoming events in a window.</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"orderbyfieldpaths\"><code>orderByFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>tournament__name</code></td>\n<td>string</td>\n<td>Case-insensitive. Default key.</td>\n</tr>\n<tr>\n<td><code>tournament__id</code></td>\n<td>UUID</td>\n<td>Stable tie-breaker. Default key.</td>\n</tr>\n<tr>\n<td><code>tournament__priority</code></td>\n<td>int</td>\n<td>Editorial sort priority (lower = higher up).</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>tournaments</code> (object, required) - <code>Page&lt;Tournament&gt;</code> envelope (see <strong>Pagination → <code>page</code></strong>).</li>\n</ul>\n<p>Tournament (<code>tournaments.edges[].node</code>):</p>\n<ul>\n<li><p><code>tournamentId</code> (string, required) - Tournament id (UUID).</p>\n</li>\n<li><p><code>tournamentName</code> (string, required) - Tournament display name.</p>\n</li>\n<li><p><code>categoryId</code> (string, required) - Parent category id (UUID).</p>\n</li>\n<li><p><code>sportId</code> (string, required) - Parent sport id (UUID). See <strong>Sports</strong>.</p>\n</li>\n</ul>\n","auth":{"type":"noauth","isInherited":true,"source":{"_postman_id":"a104990e-b123-43bf-9db7-f03dbb389c4c","id":"a104990e-b123-43bf-9db7-f03dbb389c4c","name":"Sportsbook Tree","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","sportsbook","tournaments"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"d8beabf2-6127-4c27-b94b-ed43b5f570ea","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": { \"first\": 2 },\n    \"where\": {\n        \"predicate\": \"eq\",\n        \"fieldPath\": \"tournament__categoryId\",\n        \"value\": \"22222222-2222-2222-2222-222222222222\"\n    },\n    \"order\": [\n        { \"fieldPath\": \"tournament__priority\", \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/tournaments"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"tournaments\": {\n        \"edges\": [\n            {\n                \"cursor\": \"eyJpZCI6IjMzMzMzMzMzLTMzMzMtMzMzMy0zMzMzLTMzMzMzMzMzMzMzMyJ9\",\n                \"node\": {\n                    \"tournamentId\": \"33333333-3333-3333-3333-333333333333\",\n                    \"tournamentName\": \"UEFA Champions League\",\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            },\n            {\n                \"cursor\": \"eyJpZCI6IjMzMzMzMzMzLTMzMzMtMzMzMy0zMzMzLTMzMzMzMzMzMzMzNCJ9\",\n                \"node\": {\n                    \"tournamentId\": \"33333333-3333-3333-3333-333333333334\",\n                    \"tournamentName\": \"UEFA Europa League\",\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            }\n        ],\n        \"pageInfo\": {\n            \"hasPreviousPage\": false,\n            \"hasNextPage\": true,\n            \"startCursor\": \"eyJpZCI6IjMzMzMzMzMzLTMzMzMtMzMzMy0zMzMzLTMzMzMzMzMzMzMzMyJ9\",\n            \"endCursor\": \"eyJpZCI6IjMzMzMzMzMzLTMzMzMtMzMzMy0zMzMzLTMzMzMzMzMzMzMzNCJ9\",\n            \"total\": 12\n        }\n    }\n}"}],"_postman_id":"275ca586-1d21-4790-91c0-3ea142269a5a"},{"name":"Find Events","id":"4217be49-9308-4995-8c36-18a7da8482b8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": {\n        \"first\": 50,\n        \"after\": null\n    },\n    \"where\": {\n        \"predicate\": \"and\",\n        \"operands\": [\n            { \"predicate\": \"eq\",  \"fieldPath\": \"event__tournamentId\", \"value\": \"33333333-3333-3333-3333-333333333333\" },\n            { \"predicate\": \"gte\", \"fieldPath\": \"event__startTime\",    \"value\": \"1779753600000\" },\n            { \"predicate\": \"lt\",  \"fieldPath\": \"event__startTime\",    \"value\": \"1780358400000\" },\n            { \"predicate\": \"is_null\", \"fieldPath\": \"event__finishedAt\" }\n        ]\n    },\n    \"order\": [\n        { \"fieldPath\": \"event__startTime\", \"direction\": \"ASC\" },\n        { \"fieldPath\": \"event__id\",        \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/events","description":"<p>Returns a page of sportsbook events for the given brand.</p>\n<p>Uses the shared cursor-based pagination described in the <strong>Pagination</strong> section of this folder (request fields: <code>cursor</code>, <code>where</code>, <code>order</code>; response envelope: <code>page</code>).</p>\n<hr />\n<h4 id=\"request-body-description\">Request Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>brandId</code> (int, required) - Brand id provided by aggregator provider.</p>\n</li>\n<li><p><code>brand</code> (string, optional) - Brand code, when applicable.</p>\n</li>\n<li><p><code>cursor</code> (object, optional) - Pagination cursor. See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>where</code> (object, optional) - Filter tree over <code>whereFieldPaths</code> (see below). See <strong>Pagination</strong>.</p>\n</li>\n<li><p><code>order</code> (array, optional) - Sort over <code>orderByFieldPaths</code> (see below). Default: <code>event__createdAt DESC, event__id ASC</code>.</p>\n</li>\n</ul>\n<hr />\n<h4 id=\"wherefieldpaths\"><code>whereFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>event__id</code></td>\n<td>UUID</td>\n<td>Event id.</td>\n</tr>\n<tr>\n<td><code>event__name</code></td>\n<td>string</td>\n<td>Event name. Also matches participant names (so a leaf with <code>like</code> / <code>unaccent_like</code> on <code>event__name</code> will surface events containing the substring in either the event title or one of its team names).</td>\n</tr>\n<tr>\n<td><code>event__status</code></td>\n<td>enum</td>\n<td>Event lifecycle status. Use <code>eq</code> / <code>in</code> / <code>not_in</code> with the open string values listed under <strong>Transaction Details → <code>eventStatus</code></strong> (<code>not_started</code>, <code>in_progress</code>, <code>finished</code>, <code>cancelled</code>, <code>interrupted</code>, <code>postponed</code>, <code>retired</code>, <code>corrupted</code>).</td>\n</tr>\n<tr>\n<td><code>event__sportId</code></td>\n<td>UUID</td>\n<td>Sport id. See <strong>Sports</strong> for the id → code mapping.</td>\n</tr>\n<tr>\n<td><code>event__categoryId</code></td>\n<td>UUID</td>\n<td>Category id.</td>\n</tr>\n<tr>\n<td><code>event__tournamentId</code></td>\n<td>UUID</td>\n<td>Tournament id.</td>\n</tr>\n<tr>\n<td><code>event__startTime</code></td>\n<td>timestamp</td>\n<td>Scheduled kick-off / start time. Value is <strong>epoch milliseconds as a string</strong> (e.g. <code>\"1779753600000\"</code>) or a relative date token (<code>P1D</code>, <code>MD</code>, <code>-P1H</code>, <code>MD_TZEurope/Berlin</code>, ...). See <strong>Pagination → Timestamp values</strong>. Use with <code>gt</code> / <code>gte</code> / <code>lt</code> / <code>lte</code>.</td>\n</tr>\n<tr>\n<td><code>betting__status</code></td>\n<td>enum</td>\n<td>Betting status (open / suspended / closed). Use <code>eq</code> / <code>in</code>.</td>\n</tr>\n<tr>\n<td><code>event__finishedAt</code></td>\n<td>timestamp</td>\n<td>Time when the event was marked finished. Same value format as <code>event__startTime</code> (epoch millis / relative). Use <code>is_null</code> to fetch upcoming/live events, <code>is_not_null</code> for settled events, or <code>gte</code> / <code>lte</code> for time windows.</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"orderbyfieldpaths\"><code>orderByFieldPaths</code></h4>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>fieldPath</th>\n<th>type</th>\n<th>notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>event__createdAt</code></td>\n<td>timestamp</td>\n<td>Default key, default direction <code>DESC</code>.</td>\n</tr>\n<tr>\n<td><code>event__id</code></td>\n<td>UUID</td>\n<td>Default key. Stable tie-breaker.</td>\n</tr>\n<tr>\n<td><code>event__startTime</code></td>\n<td>timestamp</td>\n<td>Sort by scheduled start.</td>\n</tr>\n<tr>\n<td><code>event__name</code></td>\n<td>string</td>\n<td>Sort by event name.</td>\n</tr>\n<tr>\n<td><code>event__status</code></td>\n<td>enum</td>\n<td>Sort by event status.</td>\n</tr>\n<tr>\n<td><code>betting__status</code></td>\n<td>enum</td>\n<td>Sort by betting status.</td>\n</tr>\n<tr>\n<td><code>event__betsCount</code></td>\n<td>int</td>\n<td>Sort by number of bets placed on the event.</td>\n</tr>\n</tbody>\n</table>\n</div><hr />\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><code>events</code> (object, required) - <code>Page&lt;Event&gt;</code> envelope (see <strong>Pagination → <code>page</code></strong>).</li>\n</ul>\n<p>Event (<code>events.edges[].node</code>):</p>\n<ul>\n<li><p><code>eventId</code> (string, required) - Event id (UUID).</p>\n</li>\n<li><p><code>eventName</code> (string, required) - Event display name.</p>\n</li>\n<li><p><code>eventStartTime</code> (string, required) - Scheduled start time as ISO-8601 instant.</p>\n</li>\n<li><p><code>tournamentId</code> (string, required) - Parent tournament id (UUID).</p>\n</li>\n<li><p><code>categoryId</code> (string, required) - Parent category id (UUID).</p>\n</li>\n<li><p><code>sportId</code> (string, required) - Parent sport id (UUID). See <strong>Sports</strong>.</p>\n</li>\n</ul>\n","auth":{"type":"noauth","isInherited":true,"source":{"_postman_id":"a104990e-b123-43bf-9db7-f03dbb389c4c","id":"a104990e-b123-43bf-9db7-f03dbb389c4c","name":"Sportsbook Tree","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","sportsbook","events"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"6546a008-434d-4796-8295-ad779c3531f7","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"brand\": null,\n    \"cursor\": { \"first\": 2 },\n    \"where\": {\n        \"predicate\": \"and\",\n        \"operands\": [\n            { \"predicate\": \"eq\",  \"fieldPath\": \"event__tournamentId\", \"value\": \"33333333-3333-3333-3333-333333333333\" },\n            { \"predicate\": \"is_null\", \"fieldPath\": \"event__finishedAt\" }\n        ]\n    },\n    \"order\": [\n        { \"fieldPath\": \"event__startTime\", \"direction\": \"ASC\" }\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/sportsbook/events"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"events\": {\n        \"edges\": [\n            {\n                \"cursor\": \"eyJpZCI6IjQ0NDQ0NDQ0LTQ0NDQtNDQ0NC00NDQ0LTQ0NDQ0NDQ0NDQ0NCJ9\",\n                \"node\": {\n                    \"eventId\": \"44444444-4444-4444-4444-444444444444\",\n                    \"eventName\": \"Real Madrid vs Manchester City\",\n                    \"eventStartTime\": \"2026-05-28T20:00:00Z\",\n                    \"tournamentId\": \"33333333-3333-3333-3333-333333333333\",\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            },\n            {\n                \"cursor\": \"eyJpZCI6IjQ0NDQ0NDQ0LTQ0NDQtNDQ0NC00NDQ0LTQ0NDQ0NDQ0NDQ0NSJ9\",\n                \"node\": {\n                    \"eventId\": \"44444444-4444-4444-4444-444444444445\",\n                    \"eventName\": \"Bayern Munich vs Paris Saint-Germain\",\n                    \"eventStartTime\": \"2026-05-29T20:00:00Z\",\n                    \"tournamentId\": \"33333333-3333-3333-3333-333333333333\",\n                    \"categoryId\": \"22222222-2222-2222-2222-222222222222\",\n                    \"sportId\": \"d6934640-cf1d-11e9-864b-0242ac13000a\"\n                }\n            }\n        ],\n        \"pageInfo\": {\n            \"hasPreviousPage\": false,\n            \"hasNextPage\": true,\n            \"startCursor\": \"eyJpZCI6IjQ0NDQ0NDQ0LTQ0NDQtNDQ0NC00NDQ0LTQ0NDQ0NDQ0NDQ0NCJ9\",\n            \"endCursor\": \"eyJpZCI6IjQ0NDQ0NDQ0LTQ0NDQtNDQ0NC00NDQ0LTQ0NDQ0NDQ0NDQ0NSJ9\",\n            \"total\": 8\n        }\n    }\n}"}],"_postman_id":"4217be49-9308-4995-8c36-18a7da8482b8"}],"id":"a104990e-b123-43bf-9db7-f03dbb389c4c","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"5e856d92-aecd-4db4-95b6-b7e4d447ea31"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"e6db0630-203c-49ef-a194-fc7008c6490d"}}],"_postman_id":"a104990e-b123-43bf-9db7-f03dbb389c4c","description":""}],"id":"bec549e2-3937-4f1e-ba97-2fa3cc787b72","description":"<p>Reference structures for the sportsbook-specific payloads attached to Casino API callbacks (Transaction, End Round).</p>\n<p>When the originating transaction comes from a sportsbook bet, the request body carries an extra <code>details</code> object alongside the regular casino fields. Casino game transactions leave it null.</p>\n<p>This folder documents:</p>\n<ul>\n<li><p><strong>Transaction Details</strong> - the full <code>details</code> object schema and an example payload.</p>\n</li>\n<li><p><strong>Sports</strong> - shared reference table mapping <code>sportId</code> (UUID) to its sport code; used by both Event Pick and Outright Pick.</p>\n</li>\n<li><p><strong>Bet Structure</strong> - structural summary of the bet (single / parlay / system, banker count) exposed at <code>details.bet.betStructure</code>.</p>\n</li>\n<li><p><strong>Outcome</strong> - the <code>outcome</code> object on an Event Pick: <code>scopeName</code>, <code>scopeNumber</code>, <code>scoreType</code>, <code>marketGroup</code>, <code>marketParameters</code> map and <code>outcomeParameters</code> map. Enumerates all possible values per field.</p>\n</li>\n</ul>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"0806bc3d-67f2-42f5-8b4d-e965aa4186a1"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"0dbb0f20-9301-4e84-b0e9-9194de5021f0"}}],"_postman_id":"bec549e2-3937-4f1e-ba97-2fa3cc787b72"},{"name":"Affiliate API","item":[{"name":"Aggregator API","item":[{"name":"Register User","id":"9101e116-25ac-4536-9c8a-d83a824b9f75","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"username\": \"mehmet.demir\",\n    \"name\": \"Mehmet\",\n    \"surname\": \"Demir\",\n    \"honorific\": \"Mr\",\n    \"locale\": \"tr_TR\",\n    \"currency\": \"TRY\",\n    \"tracker\": {\n        \"type\": \"TRACKING_CODE\",\n        \"value\": \"ABHoQxDbREpLTHMp18gbAL6wZw\"\n    },\n    \"promoCode\": \"WELCOME\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/register","description":"<h1 id=\"endpoint-for-customer-registration\">Endpoint for Customer Registration</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/affiliate/users/register</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint allows external casino systems to register affiliate users. The system supports idempotent operations - if a user with the same <code>externalUserId</code> and <code>brandId</code> already exists, the stored user data is returned instead of creating a duplicate.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><code>brandId</code> (Int, required) - Brand id provided by aggregator provider. Must be a valid brand identifier.</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - Unique identifier of the user in the casino system. Must be unique among all users for the same brand. Cannot be blank.</p>\n</li>\n<li><p><code>username</code> (string, required) - Username for the user. Cannot be blank.</p>\n</li>\n<li><p><code>name</code> (string, optional) - First name of the user. Can be null.</p>\n</li>\n<li><p><code>surname</code> (string, optional) - Last name of the user. Can be null.</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Honorific title for the user. Please refer to the common API documentation for honorific enum values. Can be null.</p>\n</li>\n<li><p><code>locale</code> (enum, required) - Locale code for the user. Please refer to the common API documentation for locale enum values. Must be a valid locale enum value.</p>\n</li>\n<li><p><code>currency</code> (string, required) - Currency code. Must be a valid currency code and cannot be blank. Please refer to the common API documentation for currency code rules.</p>\n</li>\n<li><p><code>tracker</code> (object, optional) - Tracking information for affiliate attribution. Can be null if the user registration should not be attributed to any affiliate. If provided, must be a valid tracker object. The tracker object has the following structure:</p>\n<ul>\n<li><p><code>type</code> (enum, required) - Tracker type. Valid values:</p>\n<ul>\n<li><p><code>TRACKING_CODE</code> - Tracking code type</p>\n</li>\n<li><p><code>LINK_CODE</code> - Link code type</p>\n</li>\n</ul>\n</li>\n<li><p><code>value</code> (string, required) - Tracker value. The value must be non-empty and cannot be blank. This validation applies to both <code>TRACKING_CODE</code> and <code>LINK_CODE</code> tracker types.</p>\n</li>\n</ul>\n</li>\n<li><p><code>promoCode</code> (string, optional) - Promotional code associated with the registration. Can be null.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><code>internalUserId</code> (string, required) - Internal user identifier in the aggregator provider system. This is a unique identifier generated by the system and can be used for future reference or queries.</p>\n</li>\n<li><p><code>externalUserId</code> (string, required) - User identifier from the request. If a user with this <code>externalUserId</code> and <code>brandId</code> already exists, the stored value is returned (idempotent behavior).</p>\n</li>\n<li><p><code>brandId</code> (integer, required) - Brand id from the request. If the user already exists, the stored value is returned.</p>\n</li>\n<li><p><code>createdAt</code> (long, required) - Created at timestamp when the user was registered. If the user already exists, the stored value is returned. Please refer to the common API documentation for timestamp format rules.</p>\n</li>\n<li><p><code>referrer</code> (object, optional) - Referrer information if the user was referred by an affiliate. Can be null if no referrer is associated with the user. The referrer object has the following structure:</p>\n<ul>\n<li><p><code>type</code> (enum, required) - Referrer type. Valid values:</p>\n<ul>\n<li><code>AFFILIATE</code> - User was referred by an affiliate</li>\n</ul>\n</li>\n<li><p><code>id</code> (string, required) - Referrer identifier (UUID format). Unique identifier of the referrer.</p>\n</li>\n</ul>\n</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>**When** **`referrer`** **is null:**\n- No `tracker` was provided in the request (user registered without attribution)\n- The `tracker` value provided in the request could not be resolved to a valid referrer (affiliate)\n- The tracker value does not exist in the system or is invalid\n- No referrer was associated with the user during registration\n**When** **`referrer`** **is not null:**\n- The `tracker` value provided in the request was successfully resolved to a valid referrer\n- The system identified an affiliate associated with the tracker value\n- The referrer information is returned to indicate successful attribution\n**Idempotent behavior:**\n- If a user with the same `externalUserId` and `brandId` already exists, the stored referrer value from the original registration is returned\n- This means the referrer value (null or not null) will be the same as it was during the initial registration, regardless of the tracker value in subsequent requests\n\n</code></pre><ul>\n<li><p><code>username</code> (string, optional) - Username from the request. If the user already exists, the stored value is returned. Can be null.</p>\n</li>\n<li><p><code>name</code> (string, optional) - First name from the request. If the user already exists, the stored value is returned. Can be null.</p>\n</li>\n<li><p><code>surname</code> (string, optional) - Last name from the request. If the user already exists, the stored value is returned. Can be null.</p>\n</li>\n<li><p><code>honorific</code> (enum, optional) - Honorific from the request. If the user already exists, the stored value is returned. Please refer to the common API documentation for honorific enum values. Can be null.</p>\n</li>\n<li><p><code>locale</code> (enum, required) - Locale from the request. If the user already exists, the stored value is returned. Please refer to the common API documentation for locale enum values.</p>\n</li>\n<li><p><code>currency</code> (string, optional) - Currency code from the request. If the user already exists, the stored value is returned. Please refer to the common API documentation for currency code rules. Can be null.</p>\n</li>\n</ul>\n<h2 id=\"request-example\">Request Example</h2>\n<h3 id=\"registration-with-tracking-code\">Registration with Tracking Code</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-abc-123\",\n  \"username\": \"johndoe\",\n  \"name\": \"John\",\n  \"surname\": \"Doe\",\n  \"honorific\": \"MR\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\",\n  \"tracker\": {\n    \"type\": \"TRACKING_CODE\",\n    \"value\": \"tracking-code-12345\"\n  },\n  \"promoCode\": \"WELCOME2024\"\n}\n\n</code></pre>\n<h3 id=\"registration-with-link-code\">Registration with Link Code</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-xyz-789\",\n  \"username\": \"janedoe\",\n  \"name\": \"Jane\",\n  \"surname\": \"Doe\",\n  \"locale\": \"en_GB\",\n  \"currency\": \"GBP\",\n  \"tracker\": {\n    \"type\": \"LINK_CODE\",\n    \"value\": \"link-code-67890\"\n  }\n}\n\n</code></pre>\n<h3 id=\"minimal-registration\">Minimal Registration</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-minimal-456\",\n  \"username\": \"minimaluser\",\n  \"locale\": \"tr_TR\",\n  \"currency\": \"TRY\",\n  \"tracker\": {\n    \"type\": \"TRACKING_CODE\",\n    \"value\": \"tracking-code-11111\"\n  }\n}\n\n</code></pre>\n<h3 id=\"registration-without-attribution\">Registration without Attribution</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-no-attribution-789\",\n  \"username\": \"directuser\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\"\n}\n\n</code></pre>\n<h2 id=\"response-example\">Response Example</h2>\n<h3 id=\"successful-response-200-ok\">Successful Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"internalUserId\": \"internal-user-uuid-12345\",\n  \"externalUserId\": \"user-abc-123\",\n  \"brandId\": 1,\n  \"createdAt\": 1704067200000,\n  \"referrer\": null,\n  \"username\": \"johndoe\",\n  \"name\": \"John\",\n  \"surname\": \"Doe\",\n  \"honorific\": \"MR\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\"\n}\n\n</code></pre>\n<h3 id=\"successful-response-with-referrer-200-ok\">Successful Response with Referrer (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"internalUserId\": \"internal-user-uuid-12345\",\n  \"externalUserId\": \"user-abc-123\",\n  \"brandId\": 1,\n  \"createdAt\": 1704067200000,\n  \"referrer\": {\n    \"type\": \"AFFILIATE\",\n    \"id\": \"550e8400-e29b-41d4-a716-446655440000\"\n  },\n  \"username\": \"johndoe\",\n  \"name\": \"John\",\n  \"surname\": \"Doe\",\n  \"honorific\": \"MR\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\"\n}\n\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li><p>Missing required fields</p>\n</li>\n<li><p>Invalid field formats (e.g., invalid currency code, invalid enum value)</p>\n</li>\n<li><p>Blank values for required string fields</p>\n</li>\n<li><p>Invalid tracker format or value (if tracker is provided)</p>\n</li>\n<li><p>Invalid tracker type (if tracker is provided)</p>\n</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Request validation failed\",\n  \"message\": \"Field 'currency' must be a valid currency code\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---invalid-tracker\">400 Bad Request - Invalid Tracker</h3>\n<p>Occurs when a tracker is provided but the format or value is invalid. Common causes:</p>\n<ul>\n<li><p>Missing <code>type</code> or <code>value</code> field in tracker object</p>\n</li>\n<li><p>Invalid tracker <code>type</code> (must be <code>TRACKING_CODE</code> or <code>LINK_CODE</code>)</p>\n</li>\n<li><p>Blank or empty tracker <code>value</code></p>\n</li>\n</ul>\n<p><strong>Note:</strong> This error only occurs when a tracker object is provided. If no tracker is provided, the registration will succeed without attribution.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Request validation failed\",\n  \"message\": \"Tracker value should be valid tracking code\"\n}\n\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<p>Occurs when an unexpected server error happens.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Unknown error\",\n  \"message\": \"An unexpected error occurred\"\n}\n\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Idempotency</strong>: The endpoint is idempotent. If you send the same request (same <code>externalUserId</code> and <code>brandId</code>) multiple times, you will receive the same response with the stored user data. This prevents duplicate user registrations.</p>\n</li>\n<li><p><strong>User Uniqueness</strong>: The combination of <code>externalUserId</code> and <code>brandId</code> must be unique. Attempting to register a user with the same <code>externalUserId</code> and <code>brandId</code> but different data will return the existing user.</p>\n</li>\n<li><p><strong>Tracker and Attribution</strong>:</p>\n<ul>\n<li><p>The <code>tracker</code> field is optional. If not provided, the user will be created without attribution (the <code>referrer</code> field in the response will be null)</p>\n</li>\n<li><p>If <code>tracker</code> is provided, it must contain a valid tracker object</p>\n</li>\n<li><p>The tracker <code>type</code> must be either <code>TRACKING_CODE</code> or <code>LINK_CODE</code></p>\n</li>\n<li><p>The tracker <code>value</code> must be non-empty and cannot be blank for both tracker types</p>\n</li>\n<li><p>If a valid tracker is provided and can be resolved, the <code>referrer</code> field in the response will contain the referrer information</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Currency Codes</strong>: Please refer to the common API documentation for currency code rules.</p>\n</li>\n<li><p><strong>Locale Values</strong>: Please refer to the common API documentation for locale enum values.</p>\n</li>\n<li><p><strong>Honorific Values</strong>: Please refer to the common API documentation for honorific enum values.</p>\n</li>\n<li><p><strong>Timestamp Format</strong>: Please refer to the common API documentation for timestamp format rules.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires authentication. Please refer to the authentication documentation for details on how to include authentication headers in your requests.</p>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"33842f32-77e6-4695-b800-7331205900bf","id":"33842f32-77e6-4695-b800-7331205900bf","name":"Affiliate API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","affiliate","users","register"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"b4828a0e-4640-4cf4-8504-e3e42eaf1d79","name":"success","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"username\": \"mehmet.demir\",\n    \"name\": \"Mehmet\",\n    \"surname\": \"Demir\",\n    \"honorific\": \"Mr\",\n    \"locale\": \"tr_TR\",\n    \"currency\": \"TRY\",\n    \"tracker\": {\n        \"type\": \"TRACKING_CODE\",\n        \"value\": \"ABHoQxDbREpLTHMp18gbAL6wZw\"\n    },\n    \"promoCode\": \"WELCOME\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/register"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"internalUserId\": \"019a3409-eace-739e-ae71-83b41d323375\",\n    \"externalUserId\": \"ext_987654321\",\n    \"brandId\": 0,\n    \"createdAt\": 1761721205143,\n    \"referrer\": {\n        \"id\": \"019a33fe-a05d-71bc-91fc-2ee9ca31ae1b\",\n        \"type\": \"AFFILIATE\"\n    },\n    \"username\": \"mehmet.demir\",\n    \"name\": \"Mehmet\",\n    \"surname\": \"Demir\",\n    \"honorific\": \"Mr\",\n    \"locale\": \"tr_TR\",\n    \"currency\": \"TRY\"\n}"},{"id":"7068e523-d97f-4dd1-82d9-7ffce5cbf039","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Authorization","value":"Basic e3VzZXJuYW1lfTp7cGFzc3dvcmR9","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"username\": \"mehmet.demir\",\n    \"name\": \"Mehmet\",\n    \"surname\": \"Demir\",\n    \"honorific\": \"Mr\",\n    \"locale\": \"tr_TR\",\n    \"currency\": \"TRY\",\n    \"tracker\": {\n        \"type\": \"TRACKING_CODE\",\n        \"value\": \"ABHoQxDbREpLTHMp18gbAL6wZw\"\n    },\n    \"promoCode\": \"WELCOME\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/register"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n  \"errorCode\": 107,\n  \"errorMessage\": \"User creation failed\"\n}"}],"_postman_id":"9101e116-25ac-4536-9c8a-d83a824b9f75"},{"name":"Create User Financial Transaction","id":"c765f93b-0157-4935-8179-fcd7ac23b083","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"DEPOSIT\",\n    \"amount\": 100,\n    \"currency\": \"TRY\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/transactions/financial/create","description":"<h1 id=\"endpoint-for-creating-affiliate-user-financial-transaction\">Endpoint for Creating Affiliate User Financial Transaction</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/affiliate/users/transactions/financial/create</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint allows external casino systems to create financial transactions for affiliate users. The system supports idempotent operations - if a transaction with the same <code>externalTxId</code> and <code>brandId</code> already exists, the stored transaction data is returned instead of creating a duplicate.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by aggregator provider. Must be a valid brand identifier.</p>\n</li>\n<li><p><strong>externalTxId</strong> (string, required) - Unique identifier of the transaction in the casino system. Must be unique among all transactions for the same brand. Cannot be blank.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - User identifier in the casino system. Must match a previously registered affiliate user. Cannot be blank.</p>\n</li>\n<li><p><strong>createdAt</strong> (long, required) - Timestamp when the transaction was created. Must be a valid long integer. Please refer to the common API documentation for timestamp format rules.</p>\n</li>\n<li><p><strong>txType</strong> (enum, required) - Type of financial transaction. Valid values:</p>\n<ul>\n<li><p><code>DEPOSIT</code> - Funds deposited to the user account</p>\n</li>\n<li><p><code>WITHDRAWAL</code> - Funds withdrawn from the user account</p>\n</li>\n<li><p><code>ROLLBACK</code> - Transaction rollback (requires <code>rolledBackExternalTxId</code>)</p>\n</li>\n</ul>\n</li>\n<li><p><strong>amount</strong> (integer, required) - Transaction amount. Must be a valid integer. Please refer to the common API documentation for amount format rules.</p>\n</li>\n<li><p><strong>currency</strong> (string, required) - Currency code. Must be a valid currency code and cannot be blank. Please refer to the common API documentation for currency code rules.</p>\n</li>\n<li><p><strong>rolledBackExternalTxId</strong> (string, optional) - Identifier of the transaction being rolled back. Required when <code>txType</code> is <code>ROLLBACK</code>. Must reference an existing transaction that was previously created. Can be null for <code>DEPOSIT</code> and <code>WITHDRAWAL</code> transaction types.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>txId</strong> (string, required) - Internal transaction identifier in the aggregator provider system. This is a unique identifier generated by the system and can be used for future reference or queries.</p>\n</li>\n<li><p><strong>externalTxId</strong> (string, required) - Transaction identifier from the request. If a transaction with this <code>externalTxId</code> and <code>brandId</code> already exists, the stored value is returned (idempotent behavior).</p>\n</li>\n<li><p><strong>brandId</strong> (integer, required) - Brand id from the request. If the transaction already exists, the stored value is returned.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - User identifier in the casino system from the request. If the transaction already exists, the stored value is returned.</p>\n</li>\n<li><p><strong>createdAt</strong> (long, required) - Created at timestamp from the request. If the transaction already exists, the stored value is returned. Please refer to the common API documentation for timestamp format rules.</p>\n</li>\n<li><p><strong>txType</strong> (enum, required) - Transaction type from the request. Valid values: <code>DEPOSIT</code>, <code>WITHDRAWAL</code>, <code>ROLLBACK</code>. If the transaction already exists, the stored value is returned.</p>\n</li>\n<li><p><strong>amount</strong> (integer, required) - Transaction amount from the request. If the transaction already exists, the stored value is returned. Please refer to the common API documentation for amount format rules.</p>\n</li>\n<li><p><strong>currency</strong> (string, required) - Currency code from the request. If the transaction already exists, the stored value is returned. Please refer to the common API documentation for currency code rules.</p>\n</li>\n<li><p><strong>rolledBackExternalTxId</strong> (string, optional) - Identifier of the rolled back transaction from the request. Required for rollback transactions. If the transaction already exists, the stored value is returned. Can be null for <code>DEPOSIT</code> and <code>WITHDRAWAL</code> transaction types.</p>\n</li>\n</ul>\n<h2 id=\"request-example\">Request Example</h2>\n<h3 id=\"deposit-transaction\">Deposit Transaction</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalTxId\": \"tx-deposit-12345\",\n  \"externalUserId\": \"user-abc-123\",\n  \"createdAt\": 1704067200000,\n  \"txType\": \"DEPOSIT\",\n  \"amount\": 10000,\n  \"currency\": \"USD\"\n}\n\n</code></pre>\n<h3 id=\"withdrawal-transaction\">Withdrawal Transaction</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalTxId\": \"tx-withdrawal-67890\",\n  \"externalUserId\": \"user-abc-123\",\n  \"createdAt\": 1704067300000,\n  \"txType\": \"WITHDRAWAL\",\n  \"amount\": 5000,\n  \"currency\": \"EUR\"\n}\n\n</code></pre>\n<h3 id=\"rollback-transaction\">Rollback Transaction</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalTxId\": \"tx-rollback-11111\",\n  \"externalUserId\": \"user-abc-123\",\n  \"createdAt\": 1704067400000,\n  \"txType\": \"ROLLBACK\",\n  \"amount\": 10000,\n  \"currency\": \"USD\",\n  \"rolledBackExternalTxId\": \"tx-deposit-12345\"\n}\n\n</code></pre>\n<h2 id=\"response-example\">Response Example</h2>\n<h3 id=\"successful-response-200-ok\">Successful Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"txId\": \"internal-tx-uuid-12345\",\n  \"externalTxId\": \"tx-deposit-12345\",\n  \"brandId\": 1,\n  \"externalUserId\": \"user-abc-123\",\n  \"createdAt\": 1704067200000,\n  \"txType\": \"DEPOSIT\",\n  \"amount\": 10000,\n  \"currency\": \"USD\",\n  \"rolledBackExternalTxId\": null\n}\n\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li><p>Missing required fields</p>\n</li>\n<li><p>Invalid field formats (e.g., invalid currency code, invalid enum value)</p>\n</li>\n<li><p>Blank values for required string fields</p>\n</li>\n<li><p>Invalid integer or long values</p>\n</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Request validation failed\",\n  \"message\": \"Field 'currency' must be a valid currency code\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<p>Occurs when the <code>externalUserId</code> does not exist in the system (user not registered).</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Invalid user\",\n  \"message\": \"User with externalUserId 'user-abc-123' not found\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---rolled-back-transaction-not-found\">400 Bad Request - Rolled Back Transaction Not Found</h3>\n<p>Occurs when <code>txType</code> is <code>ROLLBACK</code> but the <code>rolledBackExternalTxId</code> references a transaction that does not exist.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Rolled back transaction not found\",\n  \"message\": \"Transaction with externalTxId 'tx-deposit-12345' not found\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---missing-rolled-back-transaction-id\">400 Bad Request - Missing Rolled Back Transaction ID</h3>\n<p>Occurs when <code>txType</code> is <code>ROLLBACK</code> but <code>rolledBackExternalTxId</code> is not provided.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Missing rolled back transaction ID\",\n  \"message\": \"rolledBackExternalTxId is required for ROLLBACK transactions\"\n}\n\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<p>Occurs when an unexpected server error happens.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"error\": \"Unknown error\",\n  \"message\": \"An unexpected error occurred\"\n}\n\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Idempotency</strong>: The endpoint is idempotent. If you send the same request (same <code>externalTxId</code> and <code>brandId</code>) multiple times, you will receive the same response with the stored transaction data. This prevents duplicate transactions.</p>\n</li>\n<li><p><strong>Transaction Uniqueness</strong>: The combination of <code>externalTxId</code> and <code>brandId</code> must be unique. Attempting to create a transaction with the same <code>externalTxId</code> and <code>brandId</code> but different data will return the existing transaction.</p>\n</li>\n<li><p><strong>User Registration</strong>: The <code>externalUserId</code> must reference a user that was previously registered through the affiliate user registration endpoint.</p>\n</li>\n<li><p><strong>Rollback Transactions</strong>:</p>\n<ul>\n<li><p>When <code>txType</code> is <code>ROLLBACK</code>, the <code>rolledBackExternalTxId</code> field is required</p>\n</li>\n<li><p>The <code>rolledBackExternalTxId</code> must reference an existing transaction (DEPOSIT or WITHDRAWAL)</p>\n</li>\n<li><p>The <code>amount</code> in a rollback transaction should typically match the amount of the original transaction</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Amount Format</strong>: Please refer to the common API documentation for amount format rules.</p>\n</li>\n<li><p><strong>Currency Codes</strong>: Please refer to the common API documentation for currency code rules.</p>\n</li>\n<li><p><strong>Timestamp Format</strong>: Please refer to the common API documentation for timestamp format rules.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires authentication. Please refer to the authentication documentation for details on how to include authentication headers in your requests.</p>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"33842f32-77e6-4695-b800-7331205900bf","id":"33842f32-77e6-4695-b800-7331205900bf","name":"Affiliate API","type":"folder"}},"urlObject":{"path":["external-casino-client","v1","affiliate","users","transactions","financial","create"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"b5afda67-41cc-4de3-8754-d09a99a60cd6","name":"success","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"DEPOSIT\",\n    \"amount\": 100,\n    \"currency\": \"TRY\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/transactions/financial/create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n    \"txId\": \"019a3404-b7f5-7b9e-abc3-1a3318c0b245\",\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"DEPOSIT\",\n    \"amount\": 100,\n    \"currency\": \"TRY\"\n}"},{"id":"ebbd70a6-e005-4785-be0c-726397bc864e","name":"success rollback","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"ROLLBACK\",\n    \"amount\": 100,\n    \"currency\": \"TRY\",\n    \"rolledBackExternalTxId\": \"ext_787654323\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/transactions/financial/create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n    \"txId\": \"019a3404-b7f5-7b9e-abc3-1a3318c0b245\",\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"ROLLBACK\",\n    \"amount\": 100,\n    \"currency\": \"TRY\",\n    \"rolledBackExternalTxId\": \"ext_787654323\"\n}"},{"id":"7f4441a8-ac71-443e-becd-92145af5c951","name":"fail","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"externalTxId\": \"ext_787654324\",\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"createdAt\": 1761721205143,\n    \"txType\": \"DEPOSIT\",\n    \"amount\": 100,\n    \"currency\": \"TRY\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/users/transactions/financial/create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n  \"errorCode\": 109,\n  \"errorMessage\": \"Invalid User\"\n}"}],"_postman_id":"c765f93b-0157-4935-8179-fcd7ac23b083"},{"name":"Get Affiliate Profile","id":"3f2a340c-95f4-4f10-8f3d-77c29050bc95","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"resolver\": {\n        \"type\": \"TRACKER\",\n        \"tracker\": {\n            \"type\": \"TRACKING_CODE\",\n            \"value\": \"AAJpzQHEQm5wU2wvSSizCB1ZwRzSeB\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/external-casino-client/v1/affiliate/profile/get","description":"<h1 id=\"endpoint-for-fetching-affiliate-profile\">Endpoint for Fetching Affiliate Profile</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/affiliate/profile/get</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint allows external casino systems to retrieve affiliate profile information. The affiliate can be resolved either by direct ID or by a tracker (link code or tracking code).</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by aggregator provider. Must be a valid brand identifier.</p>\n</li>\n<li><p><strong>resolver</strong> (object, required) - Defines how to resolve the affiliate. Uses polymorphic deserialization based on the <code>type</code> discriminator field. The resolver object has the following structure:</p>\n<ul>\n<li><p><strong>type</strong> (enum, required) - Resolution strategy type. Valid values:</p>\n<ul>\n<li><p><code>ID</code> - Resolve affiliate directly by identifier</p>\n</li>\n<li><p><code>TRACKER</code> - Resolve affiliate by tracker (link code or tracking code)</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<p><strong>When</strong> <strong><code>type</code></strong> <strong>is</strong> <strong><code>ID</code></strong>:</p>\n<ul>\n<li><strong>id</strong> (string, required) - Affiliate identifier in UUID format. Cannot be blank. Maximum length: 36 characters. Must reference an existing affiliate in the system.</li>\n</ul>\n<p><strong>When</strong> <strong><code>type</code></strong> <strong>is</strong> <strong><code>TRACKER</code></strong>:</p>\n<ul>\n<li><p><strong>tracker</strong> (object, required) - Tracking information used to resolve the affiliate. The tracker object has the following structure:</p>\n<ul>\n<li><p><strong>type</strong> (enum, required) - Tracker type. Valid values:</p>\n<ul>\n<li><p><code>TRACKING_CODE</code> - Tracking code type</p>\n</li>\n<li><p><code>LINK_CODE</code> - Link code type</p>\n</li>\n</ul>\n</li>\n<li><p><strong>value</strong> (string, required) - Tracker value. The value must be non-empty and cannot be blank. This validation applies to both <code>TRACKING_CODE</code> and <code>LINK_CODE</code> tracker types.<br />  <strong>When tracker</strong> <strong><code>type</code></strong> <strong>is</strong> <strong><code>TRACKING_CODE</code></strong>:</p>\n<ul>\n<li><p>The value must be a valid, non-expired tracking code token</p>\n</li>\n<li><p>The tracking code must resolve to an existing affiliate link in the system</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<p><strong>When tracker</strong> <strong><code>type</code></strong> <strong>is</strong> <strong><code>LINK_CODE</code></strong>:</p>\n<ul>\n<li><p>The value must be a valid link short code</p>\n</li>\n<li><p>The short code must reference an existing, non-deleted affiliate link in the system</p>\n</li>\n<li><p>If the link is not found, error code 204 (Affiliate link not found) is returned</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>id</strong> (string, required) - Affiliate identifier in the aggregator provider system. UUID format.</p>\n</li>\n<li><p><strong>username</strong> (string, optional) - Affiliate login username. Can be null if the affiliate has no login assigned.</p>\n</li>\n<li><p><strong>profile</strong> (object, required) - Affiliate personal profile information. Contains personal details of the affiliate. The profile object has the following structure:</p>\n<ul>\n<li><p><strong>name</strong> (string, optional) - Affiliate first name. Can be null.</p>\n</li>\n<li><p><strong>surname</strong> (string, optional) - Affiliate surname. Can be null.</p>\n</li>\n<li><p><strong>country</strong> (string, required) - Country ISO 3166-1 alpha-3 code (e.g., <code>FRA</code>, <code>TUR</code>, <code>USA</code>).</p>\n</li>\n<li><p><strong>locale</strong> (string, required) - Affiliate locale code (e.g., <code>tr_TR</code>, <code>en_US</code>).</p>\n</li>\n</ul>\n</li>\n<li><p><strong>status</strong> (string, required) - Affiliate account status. Possible values: <code>ACTIVE</code>, <code>SUSPENDED</code>, <code>CLOSED</code>.</p>\n</li>\n<li><p><strong>approveStatus</strong> (string, required) - Affiliate approval status. Possible values: <code>APPROVED</code>, <code>REJECTED</code>, <code>PENDING</code>.</p>\n</li>\n<li><p><strong>companyName</strong> (string, optional) - Affiliate company name. Can be null.</p>\n</li>\n</ul>\n<h2 id=\"request-examples\">Request Examples</h2>\n<h3 id=\"resolve-by-id\">Resolve by ID</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"resolver\": {\n    \"type\": \"ID\",\n    \"id\": \"019d495b-bd90-7887-9403-b253b853f460\"\n  }\n}\n\n</code></pre>\n<h3 id=\"resolve-by-link-code\">Resolve by Link Code</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"resolver\": {\n    \"type\": \"TRACKER\",\n    \"tracker\": {\n      \"type\": \"LINK_CODE\",\n      \"value\": \"abc123\"\n    }\n  }\n}\n\n</code></pre>\n<h3 id=\"resolve-by-tracking-code\">Resolve by Tracking Code</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"resolver\": {\n    \"type\": \"TRACKER\",\n    \"tracker\": {\n      \"type\": \"TRACKING_CODE\",\n      \"value\": \"AAJpzQHEQm5wU2wvSSizCB1ZwRzSeB\"\n    }\n  }\n}\n\n</code></pre>\n<h2 id=\"response-example\">Response Example</h2>\n<h3 id=\"successful-response-200-ok\">Successful Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"id\": \"019d495b-bd90-7887-9403-b253b853f460\",\n    \"username\": \"mehmet.demir\",\n    \"name\": \"Mehmet\",\n    \"surname\": \"Demir\",\n    \"country\": \"TUR\",\n    \"locale\": \"en_US\",\n    \"status\": \"ACTIVE\",\n    \"approveStatus\": \"APPROVED\",\n    \"companyName\": \"Mehmet Soft\"\n}\n\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"404-not-found---affiliate-not-found\">404 Not Found - Affiliate Not Found</h3>\n<p>Occurs when the <code>resolver.type</code> is <code>ID</code> and the provided affiliate identifier does not exist in the system.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errorCode\": 203,\n  \"errorMessage\": \"Affiliate not found\"\n}\n\n</code></pre>\n<h3 id=\"404-not-found---affiliate-link-not-found\">404 Not Found - Affiliate Link Not Found</h3>\n<p>Occurs when the <code>resolver.type</code> is <code>TRACKER</code> and the tracker value (link code or tracking code) does not resolve to an existing affiliate link.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errorCode\": 204,\n  \"errorMessage\": \"Affiliate link not found\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li><p>Missing required fields</p>\n</li>\n<li><p>Invalid field formats (e.g., invalid resolver type, invalid tracker type)</p>\n</li>\n<li><p>Blank values for required string fields</p>\n</li>\n<li><p><code>id</code> exceeds maximum length of 36 characters</p>\n</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errorCode\": 3,\n  \"errorMessage\": \"Request validation failed: '...'\"\n}\n\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<p>Occurs when an unexpected server error happens.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errorCode\": 1,\n  \"errorMessage\": \"Unknown error\"\n}\n\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Resolution Strategies</strong>: The endpoint supports two resolution strategies via the <code>resolver</code> object:</p>\n<ul>\n<li><p><code>ID</code> - Direct lookup by affiliate identifier. Fastest resolution path.</p>\n</li>\n<li><p><code>TRACKER</code> - Resolution through the affiliate tracking system. Supports both link codes and tracking codes.</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Link Code Resolution</strong>: Link codes are short codes associated with affiliate links. The link must exist and not be deleted in the system.</p>\n</li>\n<li><p><strong>Affiliate Status</strong>: The response includes both <code>status</code> and <code>approveStatus</code> fields. An affiliate is considered generally active when <code>status</code> is <code>ACTIVE</code> and <code>approveStatus</code> is <code>APPROVED</code>.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires authentication. Please refer to the authentication documentation for details on how to include authentication headers in your requests.</p>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"33842f32-77e6-4695-b800-7331205900bf","id":"33842f32-77e6-4695-b800-7331205900bf","name":"Affiliate API","type":"folder"}},"urlObject":{"path":["external-casino-client","external-casino-client","v1","affiliate","profile","get"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"61d1b136-fdcf-424d-9aa8-713f9c5bb966","name":"success by tracker","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"resolver\": {\n        \"type\": \"TRACKER\",\n        \"tracker\": {\n            \"type\": \"TRACKING_CODE\",\n            \"value\": \"AAJpzQHEQm5wU2wvSSizCB1ZwRzSeB\"\n        }\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/profile/get"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n    \"id\": \"019d495b-bd90-7887-9403-b253b853f460\",\n    \"username\": \"mehmet.demir\",\n    \"profile\": {\n        \"name\": \"Mehmet\",\n        \"surname\": \"Demir\",\n        \"country\": \"TUR\",\n        \"locale\": \"en_US\"\n    },\n    \"status\": \"ACTIVE\",\n    \"approveStatus\": \"APPROVED\",\n    \"companyName\": \"Mehmet Soft\"\n}"},{"id":"7b48e6b3-accb-4396-b4d7-4b5a58da3e46","name":"success by id","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"resolver\": {\n        \"type\": \"ID\",\n        \"id\": \"019d495b-bd90-7887-9403-b253b853f460\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/profile/get"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n    \"id\": \"019d495b-bd90-7887-9403-b253b853f460\",\n    \"username\": \"mehmet.demir\",\n    \"profile\": {\n        \"name\": \"Mehmet\",\n        \"surname\": \"Demir\",\n        \"country\": \"TUR\",\n        \"locale\": \"en_US\"\n    },\n    \"status\": \"ACTIVE\",\n    \"approveStatus\": \"APPROVED\",\n    \"companyName\": \"Mehmet Soft\"\n}"},{"id":"aaf2b926-aeb1-434a-a4e7-0dccb97656ce","name":"fail","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"resolver\": {\n        \"type\": \"ID\",\n        \"id\": \"019d495b-bd90-7887-9403-b253b853f460\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/affiliate/profile/get"},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[{"expires":"Invalid Date","domain":"","path":""}],"responseTime":null,"body":"{\n  \"errorCode\": 203,\n  \"errorMessage\": \"Affiliate not found\"\n}"}],"_postman_id":"3f2a340c-95f4-4f10-8f3d-77c29050bc95"}],"id":"ebd8ed68-4667-49ff-b277-fc4aedb21205","description":"<p>Requests sent from Casino to Aggregator Provider</p>\n","_postman_id":"ebd8ed68-4667-49ff-b277-fc4aedb21205","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":true,"source":{"_postman_id":"33842f32-77e6-4695-b800-7331205900bf","id":"33842f32-77e6-4695-b800-7331205900bf","name":"Affiliate API","type":"folder"}}}],"id":"33842f32-77e6-4695-b800-7331205900bf","description":"<h1 id=\"step-by-step-integration-guide\">Step-by-Step Integration Guide</h1>\n<h2 id=\"table-of-contents\">Table of Contents</h2>\n<ol>\n<li><p><a href=\"#getting-started\">Getting Started</a></p>\n</li>\n<li><p><a href=\"#understanding-tracking-methods\">Understanding Tracking Methods</a></p>\n</li>\n<li><p><a href=\"#tracking-codes\">Tracking Codes</a></p>\n</li>\n<li><p><a href=\"#link-codes\">Link Codes</a></p>\n</li>\n<li><p><a href=\"#tracking-domains\">Tracking Domains</a></p>\n</li>\n</ol>\n<hr />\n<h2 id=\"getting-started\">Getting Started</h2>\n<h3 id=\"prerequisites\">Prerequisites</h3>\n<p>Before starting the integration, ensure you have:</p>\n<ul>\n<li><p>Access to the aggregator provider API</p>\n</li>\n<li><p>Your <code>brandId</code> assigned by the aggregator provider</p>\n</li>\n<li><p>Authentication credentials (API keys, tokens, etc.)</p>\n</li>\n<li><p>Understanding of your casino system's user registration flow</p>\n</li>\n</ul>\n<h3 id=\"initial-setup\">Initial Setup</h3>\n<ol>\n<li><p><strong>Contact the aggregator provider</strong> to:</p>\n<ul>\n<li><p>Obtain your <code>brandId</code></p>\n</li>\n<li><p>Get API credentials and authentication details</p>\n</li>\n<li><p>Receive API endpoint URLs</p>\n</li>\n<li><p>Understand any brand-specific requirements</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Review API Documentation</strong>:</p>\n<ul>\n<li><p>Read the Customer Registration API documentation</p>\n</li>\n<li><p>Read the Financial Transaction API documentation</p>\n</li>\n<li><p>Understand request/response format</p>\n</li>\n</ul>\n</li>\n</ol>\n<hr />\n<h2 id=\"understanding-tracking-methods\">Understanding Tracking Methods</h2>\n<p>The system supports two types of tracking for affiliate attribution:</p>\n<h3 id=\"1-tracking-codes-tracking_code\">1. Tracking Codes (<code>TRACKING_CODE</code>)</h3>\n<ul>\n<li><p><strong>What it is</strong>: A unique link transaction code that attributes each redirect from an affiliate tracking link</p>\n</li>\n<li><p><strong>How it works</strong>:</p>\n<ul>\n<li><p>Generated automatically by the aggregator system for each click/redirect (unique per click)</p>\n</li>\n<li><p>Uses a special encrypted format that contains attribution information</p>\n</li>\n<li><p>Requires a tracking domain to function</p>\n</li>\n<li><p>Clicks are counted when users click the tracking link</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Use case</strong>: When you need to track individual clicks and count redirects from affiliate links</p>\n</li>\n<li><p><strong>Format</strong>: Encrypted format generated automatically by the system</p>\n</li>\n<li><p><strong>Requirement</strong>: Requires tracking domain setup</p>\n</li>\n</ul>\n<h3 id=\"2-link-codes-link_code\">2. Link Codes (<code>LINK_CODE</code>)</h3>\n<ul>\n<li><p><strong>What it is</strong>: A static code assigned to a link that can be used to attribute users</p>\n</li>\n<li><p><strong>How it works</strong>:</p>\n<ul>\n<li><p>Generated randomly when creating a link in the Back Office</p>\n</li>\n<li><p>Static code per link (doesn't change per click)</p>\n</li>\n<li><p>Can be used with Cuttly links to survive domain blocks</p>\n</li>\n<li><p>Does not count clicks</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Use case</strong>: When you need static attribution that works with short links (Cuttly) and can survive domain blocks</p>\n</li>\n<li><p><strong>Format</strong>: Randomly generated code created in Back Office</p>\n</li>\n<li><p><strong>Note</strong>: Cannot be used for postbacks (server-to-server callbacks)</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"tracking-codes\">Tracking Codes</h2>\n<h3 id=\"what-are-tracking-codes\">What are Tracking Codes?</h3>\n<p>Tracking codes are unique link transaction codes that are automatically generated by the aggregator system for each click/redirect from an affiliate tracking link. Each tracking code:</p>\n<ul>\n<li><p>Is unique per click (not static)</p>\n</li>\n<li><p>Contains encrypted attribution information</p>\n</li>\n<li><p>Enables click counting</p>\n</li>\n<li><p>Requires a tracking domain to function</p>\n</li>\n</ul>\n<h3 id=\"how-tracking-codes-work\">How Tracking Codes Work</h3>\n<ol>\n<li><p><strong>Link Creation</strong>: An affiliate link is created with a link code in the Back Office</p>\n</li>\n<li><p><strong>User Clicks</strong>: When a user clicks the tracking link, the system automatically generates a unique tracking code</p>\n</li>\n<li><p><strong>Redirect</strong>: User is redirected to your casino with the tracking code in the <code>tid</code> query parameter</p>\n</li>\n<li><p><strong>Registration</strong>: Extract the <code>tid</code> parameter and include it in the registration request</p>\n</li>\n<li><p><strong>Attribution</strong>: The system decrypts the tracking code and attributes the user to the affiliate</p>\n</li>\n<li><p><strong>Click Counting</strong>: The click is counted when the tracking link is clicked</p>\n</li>\n</ol>\n<h3 id=\"tracking-domain-url-structure\">Tracking Domain URL Structure</h3>\n<p>Tracking codes work with tracking domains using the following structure:</p>\n<p><strong>Initial Link Format:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>https://tracking.com/{link-code}\n\n</code></pre><p><strong>After Click (Redirect):</strong><br />When a user clicks the tracking link, they are redirected to your casino with a <code>tid</code> parameter:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>https://yourcasino.com/register?tid={tracking-code}\n\n</code></pre><p>The <code>tid</code> parameter contains the automatically generated tracking code (encrypted format).</p>\n<h3 id=\"how-to-use-tracking-codes\">How to Use Tracking Codes</h3>\n<h4 id=\"step-1-extract-tracking-code-from-url\">Step 1: Extract Tracking Code from URL</h4>\n<p>When a user arrives at your registration page from a tracking domain, extract the <code>tid</code> parameter:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">// Example JavaScript\nconst urlParams = new URLSearchParams(window.location.search);\nconst trackingCode = urlParams.get('tid');\n\n</code></pre>\n<h4 id=\"step-2-include-in-registration-request\">Step 2: Include in Registration Request</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-abc-123\",\n  \"username\": \"johndoe\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\",\n  \"tracker\": {\n    \"type\": \"TRACKING_CODE\",\n    \"value\": trackingCode\n  }\n}\n\n</code></pre>\n<h3 id=\"important-notes\">Important Notes</h3>\n<ul>\n<li><p><strong>Automatic Generation</strong>: Tracking codes are generated automatically - you don't create them manually</p>\n</li>\n<li><p><strong>Unique Per Click</strong>: Each click generates a new tracking code</p>\n</li>\n<li><p><strong>Encrypted Format</strong>: The tracking code uses a special encrypted format - don't try to decode or modify it</p>\n</li>\n<li><p><strong>Requires Tracking Domain</strong>: Tracking codes only work with properly configured tracking domains</p>\n</li>\n<li><p><strong>Click Counting</strong>: Clicks are counted automatically when users click the tracking link</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"link-codes\">Link Codes</h2>\n<h3 id=\"what-are-link-codes\">What are Link Codes?</h3>\n<p>Link codes are static codes assigned to affiliate links that can be used to attribute users. Unlike tracking codes:</p>\n<ul>\n<li><p><strong>Static</strong>: The same code is used for all clicks on a specific link</p>\n</li>\n<li><p><strong>No Click Counting</strong>: Clicks are not counted with link codes</p>\n</li>\n<li><p><strong>Cuttly Compatible</strong>: Typically used with URL shorteners like Cuttly</p>\n</li>\n<li><p><strong>Domain Block Survival</strong>: Can survive domain blocks through Cuttly link updates</p>\n</li>\n<li><p><strong>Query Parameter</strong>: Passed in the <code>p</code> query parameter</p>\n</li>\n</ul>\n<h3 id=\"how-link-codes-work\">How Link Codes Work</h3>\n<ol>\n<li><p><strong>Link Creation</strong>: When creating an affiliate link in the Back Office, a link code is randomly generated</p>\n</li>\n<li><p><strong>Link Distribution</strong>: The link code is embedded in the affiliate link (typically in a Cuttly short link)</p>\n</li>\n<li><p><strong>User Clicks Cuttly Link</strong>: When a user clicks the Cuttly link, they are redirected to your casino page</p>\n</li>\n<li><p><strong>Redirect with Parameter</strong>: The redirect includes the <code>p</code> query parameter containing the link code</p>\n</li>\n<li><p><strong>Extract Link Code</strong>: Extract the <code>p</code> parameter value from the URL</p>\n</li>\n<li><p><strong>User Registration</strong>: Include the link code in the registration request to the aggregator</p>\n</li>\n<li><p><strong>Attribution</strong>: The system uses the link code to attribute the user to the affiliate</p>\n</li>\n</ol>\n<h3 id=\"how-to-generate-link-codes\">How to Generate Link Codes</h3>\n<p>Link codes are <strong>generated randomly</strong> when you create a link in the Back Office:</p>\n<ol>\n<li><p>Access the Back Office</p>\n</li>\n<li><p>Create a new affiliate link</p>\n</li>\n<li><p>The system automatically generates a random link code for that link</p>\n</li>\n<li><p>The link code is static and remains the same for that specific link</p>\n</li>\n</ol>\n<h3 id=\"using-link-codes-with-cuttly-links\">Using Link Codes with Cuttly Links</h3>\n<h4 id=\"creating-cuttly-links\">Creating Cuttly Links</h4>\n<ol>\n<li><p><strong>Create Link in Back Office</strong>: Generate a link code through the Back Office</p>\n</li>\n<li><p><strong>Create Cuttly Short Link</strong>: Use the Back Office to create a Cuttly short link</p>\n</li>\n<li><p><strong>Link Format</strong>: The Cuttly link will redirect to your casino with the <code>p</code> query parameter containing the link code</p>\n</li>\n</ol>\n<h4 id=\"cuttly-link-flow\">Cuttly Link Flow</h4>\n<ol>\n<li><p><strong>User Clicks Cuttly Link</strong>: User clicks a Cuttly short link (e.g., <code>https://cutt.ly/xyz123</code>)</p>\n</li>\n<li><p><strong>Redirect to Casino</strong>: Cuttly redirects the user to your casino page</p>\n</li>\n<li><p><strong>URL with Parameter</strong>: The redirect URL includes the <code>p</code> query parameter: <code>https://yourcasino.com/register?p={link-code}</code></p>\n</li>\n<li><p><strong>Extract Parameter</strong>: Extract the <code>p</code> parameter value from the URL</p>\n</li>\n<li><p><strong>Report to Aggregator</strong>: Include the link code in the registration request to the aggregator API</p>\n</li>\n</ol>\n<h4 id=\"example-cuttly-link-flow\">Example Cuttly Link Flow</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>User clicks: https://cutt.ly/abc123\n↓\nCuttly redirects to: https://yourcasino.com/register?p=link-code-67890\n↓\nExtract p parameter: \"link-code-67890\"\n↓\nInclude in registration API:\n{\n  \"tracker\": {\n    \"type\": \"LINK_CODE\",\n    \"value\": \"link-code-67890\"\n  }\n}\n\n</code></pre><h4 id=\"domain-block-survival\">Domain Block Survival</h4>\n<p>If your casino's main domain gets blocked:</p>\n<ol>\n<li><p><strong>Domain Rotation</strong>: Your external system should notify the aggregator provider about the domain rotation</p>\n</li>\n<li><p><strong>Automatic Update</strong>: The aggregator provider updates all Cuttly short links with your new domain</p>\n</li>\n<li><p><strong>Link Continuity</strong>: All existing Cuttly links continue to work with the new domain</p>\n</li>\n<li><p><strong>No Link Recreation</strong>: You don't need to recreate or redistribute links</p>\n</li>\n<li><p><strong>Parameter Preservation</strong>: The <code>p</code> parameter is preserved through the domain update</p>\n</li>\n</ol>\n<h3 id=\"example-link-code-usage\">Example Link Code Usage</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-antlr4\">{\n  \"tracker\": {\n    \"type\": \"LINK_CODE\",\n    \"value\": \"abc123xyz789\"\n  }\n}\n\n</code></pre>\n<h3 id=\"link-code-extraction\">Link Code Extraction</h3>\n<p>Link codes are always passed in the <code>p</code> query parameter. Extract the <code>p</code> parameter value from the URL:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">// Example JavaScript - Extract p parameter\nconst urlParams = new URLSearchParams(window.location.search);\nconst linkCode = urlParams.get('p');\n\n</code></pre>\n<h4 id=\"from-cuttly-link-redirect\">From Cuttly Link Redirect</h4>\n<p>When a user clicks a Cuttly link, they are redirected to your casino page with the <code>p</code> parameter:</p>\n<p><strong>Example URL after Cuttly redirect:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>https://yourcasino.com/register?p=link-code-67890\n\n</code></pre><p><strong>Extract and use:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">const urlParams = new URLSearchParams(window.location.search);\nconst linkCode = urlParams.get('p'); // Returns \"link-code-67890\"\n\n</code></pre>\n<h4 id=\"from-tracking-domain-url\">From Tracking Domain URL</h4>\n<p>If using link codes with tracking domains, the URL format is:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>https://track.example.com/?p=abc123xyz789\n\n</code></pre><p>Extract the <code>p</code> parameter value the same way:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-javascript\">const urlParams = new URLSearchParams(window.location.search);\nconst linkCode = urlParams.get('p');\n\n</code></pre>\n<h3 id=\"important-report-link-code-to-aggregator\">Important: Report Link Code to Aggregator</h3>\n<p>After extracting the <code>p</code> parameter value, you <strong>must report it back to the aggregator</strong> in the registration API request. The link code should be included in the <code>tracker</code> field:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 1,\n  \"externalUserId\": \"user-abc-123\",\n  \"username\": \"johndoe\",\n  \"locale\": \"en_US\",\n  \"currency\": \"USD\",\n  \"tracker\": {\n    \"type\": \"LINK_CODE\",\n    \"value\": \"link-code-67890\"\n  }\n}\n\n</code></pre>\n<h3 id=\"important-notes-1\">Important Notes</h3>\n<ul>\n<li><p><strong>Static Codes</strong>: Link codes don't change per click - same code for all users clicking the same link</p>\n</li>\n<li><p><strong>No Click Counting</strong>: Link codes do not enable click counting</p>\n</li>\n<li><p><strong>Cuttly Compatible</strong>: Can be used with Cuttly short links</p>\n</li>\n<li><p><strong>Not for Postbacks</strong>: Link codes cannot be used for server-to-server postbacks (use tracking domains instead)</p>\n</li>\n<li><p><strong>Domain Block Protection</strong>: Cuttly links with link codes can be updated when domains are blocked</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"tracking-domains\">Tracking Domains</h2>\n<h3 id=\"what-are-tracking-domains\">What are Tracking Domains?</h3>\n<p>Tracking domains are custom domains (e.g., <code>track.yourbrand.com</code>) that redirect users to your casino registration page while preserving affiliate tracking information through URL parameters. Tracking domains are required for:</p>\n<ul>\n<li><p><strong>Tracking Codes</strong>: Enable click counting and automatic tracking code generation</p>\n</li>\n<li><p><strong>Postbacks</strong>: Required for server-to-server postback callbacks</p>\n</li>\n</ul>\n<h3 id=\"how-to-create-a-tracking-domain\">How to Create a Tracking Domain</h3>\n<p>Tracking domains can be easily created via the Back Office. The process is simplified and handled through the aggregator provider's interface.</p>\n<h4 id=\"step-1-access-back-office\">Step 1: Access Back Office</h4>\n<ol>\n<li><p>Log in to the Back Office</p>\n</li>\n<li><p>Navigate to the tracking domains section</p>\n</li>\n<li><p>Select the option to create a new tracking domain</p>\n</li>\n</ol>\n<h4 id=\"step-2-provide-domain-information\">Step 2: Provide Domain Information</h4>\n<ol>\n<li><p><strong>Enter your domain</strong>: Provide the domain name you want to use (e.g., <code>trackingyourbrand.com</code>)</p>\n</li>\n<li><p><strong>Domain ownership</strong>: Ensure you have ownership rights to the domain</p>\n</li>\n<li><p><strong>Submit request</strong>: Submit the domain creation request through the Back Office</p>\n</li>\n</ol>\n<h3 id=\"back-office-benefits\">Back Office Benefits</h3>\n<p>Creating tracking domains via Back Office provides:</p>\n<ul>\n<li><p>✅ <strong>Simplified process</strong>: Easy-to-use interface for domain management</p>\n</li>\n<li><p>✅ <strong>Automatic configuration</strong>: Many settings are configured automatically</p>\n</li>\n<li><p>✅ <strong>Centralized management</strong>: Manage all tracking domains in one place</p>\n</li>\n<li><p>✅ <strong>Status monitoring</strong>: Track domain status and configuration in real-time</p>\n</li>\n</ul>\n<h3 id=\"tracking-domain-url-structure-1\">Tracking Domain URL Structure</h3>\n<h4 id=\"for-tracking-codes-with-click-counting\">For Tracking Codes (with Click Counting)</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>Initial Link: https://tracking.com/{link-code}\nAfter Click: https://yourcasino.com/register?tid={tracking-code}\n\n</code></pre><ul>\n<li><p><code>{link-code}</code>: The link code created in Back Office</p>\n</li>\n<li><p><code>tid</code>: Automatically generated tracking code (encrypted format) passed in redirect</p>\n</li>\n</ul>\n<h4 id=\"for-link-codes-static-attribution\">For Link Codes (Static Attribution)</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>https://tracking.com/?p={link-code}&amp;campaign={campaign-id}&amp;source={source}\n\n</code></pre><ul>\n<li><p><code>p</code> (required): Link code identifying the affiliate</p>\n</li>\n<li><p><code>campaign</code> (optional): Campaign identifier</p>\n</li>\n<li><p><code>source</code> (optional): Traffic source identifier</p>\n</li>\n</ul>\n<hr />\n<h2 id=\"tracking-domains-vs-cuttly-links\">Tracking Domains vs Cuttly Links</h2>\n<h3 id=\"recommendation\">Recommendation</h3>\n<ul>\n<li><p><strong>Use Tracking Domains</strong> for:</p>\n<ul>\n<li><p>Production environments requiring click counting</p>\n</li>\n<li><p>Server-to-server postbacks</p>\n</li>\n</ul>\n</li>\n<li><p><strong>Use Cuttly Links</strong> for:</p>\n<ul>\n<li><p>When domain block survival is important</p>\n</li>\n<li><p>When click counting is not required</p>\n</li>\n<li><p>Server-to-server postbacks are not needed</p>\n</li>\n</ul>\n</li>\n</ul>\n<hr />\n<h2 id=\"integration-steps\">Integration Steps</h2>\n<h5 id=\"step-1-implement-user-registration-endpoint\">Step 1: Implement User Registration Endpoint</h5>\n<h5 id=\"step-2-implement-financial-transaction-endpoint\">Step 2: Implement Financial Transaction Endpoint</h5>\n<h5 id=\"step-3-implement-domain-rotation-notification\">Step 3: Implement Domain Rotation Notification</h5>\n<hr />\n<h2 id=\"support-and-resources\">Support and Resources</h2>\n<ul>\n<li><p><strong>API Documentation</strong>: See Customer Registration API and Financial Transaction API</p>\n</li>\n<li><p><strong>Contact</strong>: Reach out to the aggregator provider for:</p>\n<ul>\n<li><p>Tracking code generation</p>\n</li>\n<li><p>Tracking domain setup assistance</p>\n</li>\n<li><p>API credentials and access</p>\n</li>\n<li><p>Technical support</p>\n</li>\n</ul>\n</li>\n</ul>\n<hr />\n<h2 id=\"frequently-asked-questions\">Frequently Asked Questions</h2>\n<h3 id=\"q-how-do-i-know-if-a-tracking-code-is-valid\">Q: How do I know if a tracking code is valid?</h3>\n<p>A: When you register a user with a tracking code, check the <code>referrer</code> field in the response. If it's not null, the tracking code was successfully resolved to an affiliate.</p>\n<h3 id=\"q-can-i-use-both-tracking-codes-and-link-codes\">Q: Can I use both tracking codes and link codes?</h3>\n<p>A: Yes, but not in the same request. Choose one tracking method per registration. You can use different methods for different affiliates or campaigns.</p>\n<h3 id=\"q-what-happens-if-i-send-an-invalid-tracking-code\">Q: What happens if I send an invalid tracking code?</h3>\n<p>A: The user will be registered successfully, but the <code>referrer</code> field in the response will be <code>null</code>, indicating no affiliate attribution.</p>\n<h3 id=\"q-how-long-does-it-take-to-set-up-a-tracking-domain\">Q: How long does it take to set up a tracking domain?</h3>\n<p>A: The Back Office setup is quick, but DNS propagation in worst cases may take up to 24-48 hours. SSL certificates are usually handled automatically by the aggregator provider.</p>\n<h3 id=\"q-can-i-create-tracking-domains-myself\">Q: Can I create tracking domains myself?</h3>\n<p>A: Yes, tracking domains can be easily created via the Back Office. Simply log in, navigate to the tracking domains section, and follow the creation process.</p>\n<h3 id=\"q-do-i-need-technical-knowledge-to-create-a-tracking-domain\">Q: Do I need technical knowledge to create a tracking domain?</h3>\n<p>A: No</p>\n<h3 id=\"q-whats-the-difference-between-tracking-codes-and-link-codes\">Q: What's the difference between tracking codes and link codes?</h3>\n<p>A:</p>\n<ul>\n<li><p><strong>Tracking Codes</strong>: Automatically generated unique codes per click, encrypted format, enable click counting, require tracking domains</p>\n</li>\n<li><p><strong>Link Codes</strong>: Static codes generated randomly in Back Office, can be used with Cuttly links, don't count clicks, can survive domain blocks</p>\n</li>\n</ul>\n<h3 id=\"q-can-i-use-cuttly-links-for-postbacks\">Q: Can I use Cuttly links for postbacks?</h3>\n<p>A: No, Cuttly links cannot be used for server-to-server postbacks because they don't pass tracking parameters. You must use tracking domains for postbacks.</p>\n<h3 id=\"q-how-do-i-handle-domain-blocks-with-cuttly-links\">Q: How do I handle domain blocks with Cuttly links?</h3>\n<p>A: When your casino domain is blocked, notify the aggregator provider about the domain rotation via API.</p>\n<h3 id=\"q-do-tracking-codes-count-clicks\">Q: Do tracking codes count clicks?</h3>\n<p>A: Yes, tracking codes enable click counting. Clicks are counted automatically when users click the tracking link.</p>\n<h3 id=\"q-do-link-codes-count-clicks\">Q: Do link codes count clicks?</h3>\n<p>A: No, link codes do not count clicks. They only provide static attribution for user registration.</p>\n<hr />\n<h2 id=\"postbacks\">Postbacks</h2>\n<h3 id=\"what-are-postbacks\">What are Postbacks?</h3>\n<p>Postbacks are server-to-server callbacks used for:</p>\n<ul>\n<li><p><strong>Registration tracking</strong>: Notifying external systems when a user successfully registers</p>\n</li>\n<li><p><strong>Transaction tracking</strong>: Notifying external systems about financial transactions (first deposits, redeposits)</p>\n</li>\n</ul>\n<h3 id=\"postback-requirements\">Postback Requirements</h3>\n<ul>\n<li><p><strong>Must use Tracking Domains</strong>: Postbacks require tracking domains because they need to pass tracking parameters in server-to-server communication</p>\n</li>\n<li><p><strong>Cannot use Cuttly Links</strong>: Cuttly links do not work for postbacks because they don't pass tracking parameters through server-to-server calls</p>\n</li>\n</ul>\n<p>Contact the aggregator provider for specific postback implementation details and requirements.</p>\n","auth":{"type":"basic","basic":{"basicConfig":[{"key":"username","value":"{username}"},{"key":"password","value":"{password}"}]},"isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"249e4541-76ab-46be-9cc8-79461da04dfe"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"requests":{},"exec":[""],"id":"2c8e3708-b46f-478b-aeb4-07f8deaa604c"}}],"_postman_id":"33842f32-77e6-4695-b800-7331205900bf"},{"name":"Bonus API","item":[{"name":"Aggregator API","item":[{"name":"Find Available Bonuses","id":"ff735f49-0e6f-44aa-9cbd-5de8c0a13051","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"<h1 id=\"endpoint-for-finding-available-bonuses\">Endpoint for Finding Available Bonuses</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/bonus/find-available-bonuses</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint returns the <strong>internal sportsbook free-bet bonuses</strong> currently offered\nby the operator. Three usage modes are selected via the request body fields:</p>\n<ul>\n<li><strong>Mode 1 — All available bonuses (catalogue).</strong> <code>available: true</code>, <code>externalUserId</code>\nomitted. Returns all enabled, in-activity-window bonuses. The operator-side\n<code>\"Show For Players\"</code> visibility flag is <strong>ignored</strong> in this mode — the full catalogue\nis exposed so the partner can plan campaigns.</li>\n<li><strong>Mode 2 — Available bonuses for a specific player.</strong> <code>available: true</code>,\n<code>externalUserId</code> set. Returns only the bonuses available <em>for that player</em>: per-player\nlimits, claim eligibility rules and the operator-side visibility flag are honoured,\nand bonuses already claimed/active for the player are excluded. If the external\nplayer is unknown to Sumstats, the system attempts to register them automatically\nbefore evaluating eligibility.</li>\n<li><strong>Mode 3 — Registration bonuses only.</strong> <code>tag: \"REGISTRATION\"</code> (with or without\n<code>available</code>). Returns the subset of bonuses tagged for new-player registration flows.</li>\n</ul>\n<p>The response is <strong>not paginated</strong> — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(<code>bonusSize.__payloadKind = \"FreeBetSize\"</code>) describing the substantive offer; the\npartner is expected to discriminate on <code>__payloadKind</code> for nested polymorphic objects\n(<code>criteria</code>, <code>freeBetUseType</code>, <code>bonusSize.amount</code>).</p>\n<blockquote>\n<p><strong>Scope.</strong> This integration is purpose-built for <code>INTERNAL_FREE_BET</code> bonuses on the\nsportsbook product (<code>InternalFreeBetSportsbookCriteria</code> payload). Other bonus types\n(<code>CUSTOM</code>, <code>FIRST_DEPOSIT</code>, <code>EXTERNAL_FREE_BET</code>, <code>EXTERNAL_FREE_SPINS_WITH_WAGERING</code>,\n<code>INTERNAL_FREE_SPINS_WITH_WAGERING</code>, <code>CASHBACK</code>) and non-sportsbook free-bet\ncriteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n<code>bonusType: \"INTERNAL_FREE_BET\"</code> with\n<code>bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"</code>\nclient-side.</p>\n</blockquote>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by Sumstats. Must match the brand\nencoded in the HTTP Basic credentials. Used together with <code>Authorization</code> for\ncredential lookup.</p>\n</li>\n<li><p><strong>brand</strong> (string, optional) - Deprecated alias for <code>brandId</code>. Accepted during the\nbrand migration window only — partners on the new contract must send <code>brandId</code>.</p>\n</li>\n<li><p><strong>available</strong> (boolean, optional) - When <code>true</code> activates Mode 1 or Mode 2 selection.\nWhen omitted, <code>tag</code> must be set, otherwise the request is rejected with\n<code>BAD_REQUEST</code>.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, optional) - External player id in the operator system.\nWhen set, switches the call to Mode 2 (per-player filtering). If the player is\nunknown to Sumstats, the system attempts to register them automatically.</p>\n</li>\n<li><p><strong>tag</strong> (string, optional) - When set, must be <code>\"REGISTRATION\"</code> (case-insensitive)\nand switches the call to Mode 3. Any other value is rejected with <code>BAD_REQUEST</code>.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>bonuses</strong> (array of objects, required) - List of bonus objects matching the query.\nEmpty list when nothing matches. The partner-facing slim shape drops\ninternal/operational fields (<code>descriptionTitle</code>, <code>descriptionBonusRules</code>,\n<code>fullTermsAndConditions</code>, <code>descriptionFiles</code>, <code>isShownForPlayers</code>, <code>bonusTags</code>,\n<code>shareLimitsId</code>, <code>eligibilityClaimRulesCompletionInfo</code>, <code>notSatisfiedMatchResults</code>,\n<code>satisfiedMatchResults</code>, <code>operatorId</code>, <code>ruleIds</code>, <code>removedAt</code>, <code>updatedAt</code>,\n<code>playerGroupIds</code>, <code>bonusOverridableFeatures</code>).</p>\n<p>Each bonus object has the structure documented under <strong>Bonus Fields</strong> below.</p>\n</li>\n</ul>\n<h3 id=\"bonus-fields\">Bonus Fields</h3>\n<p>The slim partner-facing bonus shape. Field-by-field semantics:</p>\n<ul>\n<li><p><strong>id</strong> (string, required) - Bonus identifier in <strong>UUID v7</strong> format. This is the\n<em>catalogue</em> id of the bonus configuration, not a per-player id. Pass to\n<code>claim-bonus-for-player</code>, <code>activate-player-bonus</code>, <code>cancel-player-bonus</code>. Stable\nacross partner calls — repeated <code>find-available-bonuses</code> requests return the same\n<code>id</code> for the same operator-configured bonus until the operator deletes the\nconfiguration.</p>\n</li>\n<li><p><strong>name</strong> (array of <code>{locale, translate}</code>, required) - Localised bonus names. Each\nentry binds a <code>locale</code> (BCP-47 / ICU locale code, e.g. <code>en_US</code>, <code>de_DE</code>) to\nthe human-readable bonus name in that locale. Partners should pick the entry\nmatching the player's locale; when no exact match exists, fall back to <code>en_US</code> or\nthe first entry. Bonuses are guaranteed to have <strong>at least one</strong> translation\n(typically <code>en_US</code>).</p>\n</li>\n<li><p><strong>bonusType</strong> (enum, required) - High-level bonus kind. <strong>For this integration's\ncontract, the relevant value is <code>INTERNAL_FREE_BET</code>.</strong> Drives which payload shapes\nappear inside <code>bonusSize</code>. Other types may appear in the catalogue but are out of\nscope — partners should filter the response to <code>bonusType: \"INTERNAL_FREE_BET\"</code>\nclient-side.</p>\n</li>\n<li><p><strong>status</strong> (enum, required) - Lifecycle status of the bonus on the operator side.\nPossible values:</p>\n<ul>\n<li><code>NOT_STARTED</code> - Created and saved but the activity window has not started yet.</li>\n<li><code>SCHEDULED</code> - Inside the configured activity window but the bonus is scheduled to go active at a later point.</li>\n<li><code>ACTIVE</code> - Enabled and inside the activity window. Only <code>ACTIVE</code> bonuses can be claimed.</li>\n<li><code>DISABLED</code> - Operator switched the bonus off from the admin panel.</li>\n<li><code>EXPIRED</code> - Activity window has passed.</li>\n<li><code>REMOVED</code> - Operator deleted the bonus configuration. Catalogue audits only — not claimable.</li>\n</ul>\n<p>Only <code>ACTIVE</code> bonuses can be claimed — <code>find-available-bonuses</code> does not return\nnon-<code>ACTIVE</code> bonuses by default; the field is informational for catalogue audits.</p>\n</li>\n<li><p><strong>enabled</strong> (boolean, required) - <code>false</code> when the operator has explicitly disabled\nthe bonus from the admin panel. A bonus with <code>status: ACTIVE</code> and <code>enabled: false</code>\nis unavailable for new claims and will not appear in Mode 2 (per-player) responses.\nMode 1 (catalogue) responses include disabled bonuses for partner audit purposes.</p>\n</li>\n<li><p><strong>promotionCode</strong> (string, optional) - Operator-issued promotion code (e.g.\n<code>\"500TRYFREEBET\"</code>, <code>\"EPL100\"</code>). When set, the bonus is gated by the code on the\nplayer-facing surface — players can only claim it through a promo-code flow.\n<code>null</code> when the bonus is freely claimable. <strong>Partners using this integration claim\nby <code>bonusId</code> directly and bypass the promo-code gate</strong>, but the field is exposed\nso partners can mirror operator-side promo flows on their UI.</p>\n</li>\n<li><p><strong>activityTime</strong> (object, optional) - Activity window. <code>null</code> means always on\n(no time gate). The shape mirrors the internal <code>ActivityTime</code> record — at most\none of <code>timePeriod</code> / <code>timeSchedule</code> is populated:</p>\n<ul>\n<li><p><strong>timePeriod</strong> (object, optional) - Continuous activity window.</p>\n<ul>\n<li><strong>timeRange</strong> (object, required) - Half-open period.<ul>\n<li><strong>from</strong> (long, optional) - Start of the window in <strong>epoch millis (UTC)</strong>.\n<code>null</code> means open-ended start.</li>\n<li><strong>to</strong> (long, optional) - End of the window in <strong>epoch millis (UTC)</strong>.\n<code>null</code> means open-ended end.</li>\n</ul>\n</li>\n<li><strong>isShownBeforePeriod</strong> (boolean, required) - Whether the bonus is exposed\nto players before <code>timeRange.from</code>.</li>\n<li><strong>isShownAfterPeriod</strong> (boolean, required) - Whether the bonus is exposed\nafter <code>timeRange.to</code>.</li>\n<li><strong>shownBeforePeriodMinutes</strong> (long, optional) - How long before\n<code>timeRange.from</code> the bonus becomes visible.</li>\n<li><strong>shownAfterPeriodMinutes</strong> (long, optional) - How long after\n<code>timeRange.to</code> the bonus remains visible.</li>\n</ul>\n</li>\n<li><p><strong>timeSchedule</strong> (object, optional) - Recurring activity schedule.\nPolymorphic on <code>__payloadKind</code>:</p>\n<ul>\n<li><code>HoursOfDayTimeSchedule</code> — recurring hours-of-day periods (<code>periods</code>).</li>\n<li><code>DaysOfWeekTimeSchedule</code> — recurring per-day-of-week periods\n(<code>periodsByDay</code>).</li>\n<li><code>DaysOfMonthTimeSchedule</code> — recurring per-day-of-month periods\n(<code>periodsByDay</code>).</li>\n</ul>\n<p><code>null</code> when activity is window-only.</p>\n</li>\n</ul>\n<p>Outside the window the bonus is unclaimable (Sumstats responds with\n<code>BONUS_NOT_AVAILABLE</code> (303) on claim).</p>\n</li>\n<li><p><strong>timeForActivationInHours</strong> (integer, optional) - Hours after claim during which\nthe player must activate the bonus (i.e. how long the <code>CLAIMED → IN_PROGRESS</code>\ntransition is allowed). <code>null</code> = unlimited (the player bonus stays in <code>CLAIMED</code>\nuntil activation or manual cancel). Used by Sumstats to compute <code>expiredOnClaimAt</code>\non the resulting player bonus. Example: <code>168</code> means the player has seven days to\nactivate.</p>\n</li>\n<li><p><strong>currencies</strong> (array of strings, required) - Currencies the bonus supports\n(ISO 4217 codes — <code>TRY</code>, <code>EUR</code>, <code>USD</code>, …). The bonus can only be claimed by players\nwhose account currency is in this set. In Mode 2, only bonuses whose <code>currencies</code>\narray contains the player's currency are returned. Empty array indicates a\nmisconfiguration on the operator side.</p>\n</li>\n<li><p><strong>isAutoActivates</strong> (boolean, required) - When <code>true</code>, the bonus auto-activates on\nclaim — partners do <strong>not</strong> need to call <code>activate-player-bonus</code>. The\n<code>claim-bonus-for-player</code> response carries <code>status: \"IN_PROGRESS\"</code> and a populated\n<code>activatedAt</code>. When <code>false</code>, the partner must explicitly call <code>activate-player-bonus</code>\nwithin <code>timeForActivationInHours</code> hours, or the player bonus expires.</p>\n</li>\n<li><p><strong>bonusSize</strong> (object, required) - Substantive offer payload describing the\nfree-bet rule and amount. <strong>For <code>INTERNAL_FREE_BET</code> bonuses, <code>bonusSize.__payloadKind</code>\nis always <code>\"FreeBetSize\"</code>.</strong> See <strong>FreeBetSize</strong> below.</p>\n</li>\n<li><p><strong>winSize</strong> (object, optional) - Cap on potential winnings. <strong>Always <code>null</code> for\n<code>INTERNAL_FREE_BET</code> bonuses</strong> — the substantive limits are encoded inside the\nfree-bet criteria (<code>bonusSize.rule.productRules[].criteria.maxWinAllowed</code>).</p>\n</li>\n<li><p><strong>wagering</strong> (object, optional) - Wagering rules. <strong>Always <code>null</code> for\n<code>INTERNAL_FREE_BET</code> bonuses</strong> — free bets do not have a turnover requirement; the\nfree bet either wins, loses, or expires per the criteria rules.</p>\n</li>\n</ul>\n<h3 id=\"bonussize--freebetsize\"><code>bonusSize</code> — FreeBetSize</h3>\n<p>For <code>INTERNAL_FREE_BET</code> bonuses, <code>bonusSize.__payloadKind = \"FreeBetSize\"</code>. The\n<code>FreeBetSize</code> payload has two top-level fields:</p>\n<ul>\n<li><p><strong>rule</strong> (object, required) - The free-bet rule — defines per-product criteria,\nfree-bet use type, and validity. See <strong>FreeBetRule</strong> below.</p>\n</li>\n<li><p><strong>amount</strong> (object, optional) - Total monetary value handed to the player as a\nfree-bet balance when the bonus is activated. Polymorphic on <code>__payloadKind</code>. Two\npractical kinds for free bets:</p>\n<ul>\n<li><p><strong>MonetarySize</strong> - Fixed amount.</p>\n<ul>\n<li><strong>money</strong> (MoneyBag, required) - The free-bet balance. See <strong>MoneyBag</strong> below.</li>\n</ul>\n</li>\n<li><p><strong>PercentageSize</strong> - Percentage of a baseline (rare for free bets).</p>\n<ul>\n<li><strong>percentage</strong> (number, required) - Percentage value, e.g. <code>100.0</code> = 100%.</li>\n<li><strong>maxAmount</strong> (MoneyBag, optional) - Upper cap on the resulting balance.</li>\n<li><strong>minAmount</strong> (MoneyBag, optional) - Lower floor on the resulting balance.</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"bonussizerule--freebetrule\"><code>bonusSize.rule</code> — FreeBetRule</h3>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>productRules</strong> (array of <code>FreeBetProductRule</code>, required, length ≥ 1) - Per-product\nfree-bet criteria. <strong>For sportsbook free bets there is a single entry with\n<code>product: \"SPORTS\"</code>.</strong></p>\n<p>Each <code>FreeBetProductRule</code> has:</p>\n<ul>\n<li><strong>note</strong> (array of <code>{locale, translate}</code>, optional) - Operator-supplied note\ndescribing the rule, localised. <code>null</code> when no note was set.</li>\n<li><strong>title</strong> (array of <code>{locale, translate}</code>, optional) - Operator-supplied title\nfor the rule, localised. <code>null</code> when no title was set.</li>\n<li><strong>product</strong> (string, required) - For this integration's scope, always <code>\"SPORTS\"</code>.</li>\n<li><strong>criteria</strong> (object, required) - Per-product limit rules. Polymorphic on\n<code>__payloadKind</code>. <strong>For sportsbook free bets,\n<code>criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"</code>.</strong> See\n<strong>InternalFreeBetSportsbookCriteria</strong> below.</li>\n</ul>\n</li>\n<li><p><strong>validityInHours</strong> (integer, required) - Lifetime of the <em>activated</em> bonus, in\nhours. <code>0</code> = unlimited (the bonus runs until the free-bet balance is exhausted,\nthe bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\nUsed by Sumstats to compute <code>expiredAt</code> on the activated player bonus.</p>\n</li>\n<li><p><strong>note</strong> (array of <code>{locale, translate}</code>, optional) - Free-form operator note for\nthe rule as a whole, localised. <code>null</code> when no note was set.</p>\n</li>\n<li><p><strong>freeBetUseType</strong> (object, required) - How the free-bet money composes the\nplayer's stake. Polymorphic on <code>__payloadKind</code>. See <strong>FreeBetUseType union</strong> below.</p>\n</li>\n</ul>\n<h3 id=\"criteria--internalfreebetsportsbookcriteria\"><code>criteria</code> — InternalFreeBetSportsbookCriteria</h3>\n<p>For sportsbook free bets, <code>criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"</code>.\nTop-level fields:</p>\n<ul>\n<li><p><strong>filters</strong> (array of <code>InternalFreeBetSportsbookFilter</code>, required) - Filter list\nnarrowing where the free bet may be staked. <strong>An empty filter list means \"no\nnarrowing\"</strong> (the free bet may be staked on any sportsbook event). Multiple filters\nare OR'd: a stake is allowed if <strong>at least one</strong> filter accepts it. See\n<strong>InternalFreeBetSportsbookFilter</strong> below.</p>\n</li>\n<li><p><strong>minValue</strong> (MoneyBag, optional) - Minimum bet stake required. <code>null</code> = no\nminimum. Stakes below this are rejected by the bet placement engine.</p>\n</li>\n<li><p><strong>maxValue</strong> (MoneyBag, optional) - Maximum bet stake allowed. <code>null</code> = no\nmaximum. Stakes above this are rejected.</p>\n</li>\n<li><p><strong>maxWinAllowed</strong> (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\nsingle free-bet stake are capped at this amount. <code>null</code> = no cap (free bet pays\nout the full computed winnings).</p>\n</li>\n<li><p><strong>maxAmountOfBets</strong> (integer, optional) - Maximum number of bets the player may\nplace using the free-bet balance. <code>null</code> = unlimited (the bonus runs until the\nfree-bet balance is exhausted or expires). Once the limit is hit, the bonus\ntransitions to <code>COMPLETED</code> automatically.</p>\n</li>\n</ul>\n<h4 id=\"filters--internalfreebetsportsbookfilter\"><code>filters[]</code> — InternalFreeBetSportsbookFilter</h4>\n<p>Narrows the events on which the free bet may be staked. <strong>All scalar fields are\nnullable; <code>null</code> means \"no restriction on this dimension\".</strong> The filter accepts a\nstake when <em>every</em> set field matches the stake's event metadata:</p>\n<ul>\n<li><p><strong>sportId</strong> (string, optional) - Restrict to a specific sport (UUID, operator-defined\n— e.g. football, basketball, tennis). <code>null</code> = any sport.</p>\n</li>\n<li><p><strong>categoryId</strong> (string, optional) - Restrict to a category — typically a country /\nregion inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n<code>null</code> = any category.</p>\n</li>\n<li><p><strong>tournamentId</strong> (string, optional) - Restrict to a tournament inside a category\n(UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). <code>null</code> = any\ntournament.</p>\n</li>\n<li><p><strong>eventId</strong> (string, optional) - Restrict to a single event / match (UUID,\noperator-defined). <code>null</code> = any event.</p>\n</li>\n<li><p><strong>markets</strong> (array of <code>MarketType</code>, required) - Allow-listed market identifiers\nfrom the generated <code>MarketType</code> enum (lowercase enum names from the SportsbookSchema).\nExamples: <code>score_1x2</code>, <code>score_ou</code>, <code>score_dc</code>, <code>score_both_to_score_yes_no</code>,\n<code>score_ht_ft</code>, <code>score_winning_margin</code>, <code>score_exact_number</code>, <code>corner_1x2</code>,\n<code>yellow_card_1x2</code>. <strong>Empty array means any market.</strong></p>\n</li>\n<li><p><strong>betRule</strong> (object, optional) - Bet-shape restrictions. <strong>All <code>betRule</code> fields\nare nullable; <code>null</code> (or empty for set-typed fields) means \"no restriction on this\ndimension\".</strong> A stake is accepted when every set field matches.</p>\n<ul>\n<li><p><strong>betTypes</strong> (array of <code>BetHashType</code>, required) - Allowed bet types from the\n<code>BetHashType</code> enum. The JSON wire form is <strong>lowercase</strong> (set by Jackson\n<code>@JsonProperty</code> on the enum). Possible values:</p>\n<ul>\n<li><code>single</code> - A single selection bet.</li>\n<li><code>parlay</code> - Accumulator bet (multiple selections combined; all must win).\nThe <code>accumulator*</code> betRule fields below apply only to this bet type.</li>\n<li><code>system</code> - System bet (combinations of accumulators).</li>\n</ul>\n<p><strong>Empty array means any bet type.</strong></p>\n</li>\n<li><p><strong>live</strong> (boolean, optional) - <code>true</code> = live betting only, <code>false</code> = pre-match\nonly, <code>null</code> = both allowed.</p>\n</li>\n<li><p><strong>singleMinOdd</strong> (number, optional) - Minimum odd for <code>single</code> bets. Ignored\nfor non-single bet types. Applied to the bet's single odd at placement time.</p>\n</li>\n<li><p><strong>accumulatorTotalOdds</strong> (number, optional) - Minimum total odds for a <code>parlay</code>\n(the product of all selection odds). Ignored for non-<code>parlay</code> bet types.</p>\n</li>\n<li><p><strong>accumulatorAtLeastOdd</strong> (number, optional) - At least one selection in the\n<code>parlay</code> must have an odd ≥ this value. Combined with\n<code>accumulatorMinOddPerSelection</code> for fine-grained control.</p>\n</li>\n<li><p><strong>accumulatorMinNumberOfSelections</strong> (integer, optional) - Minimum number of\nlegs (selections) in the <code>parlay</code>.</p>\n</li>\n<li><p><strong>accumulatorMaxNumberOfSelections</strong> (integer, optional) - Maximum number of\nlegs in the <code>parlay</code>.</p>\n</li>\n<li><p><strong>accumulatorMinOddPerSelection</strong> (number, optional) - Minimum odd that\n<strong>every</strong> selection in the <code>parlay</code> must meet.</p>\n</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"freebetusetype--freebetusetype-union\"><code>freeBetUseType</code> — FreeBetUseType union</h3>\n<p>Discriminated by <code>__payloadKind</code>. Two concrete kinds:</p>\n<ul>\n<li><p><strong><code>FreeBetAllBalanceUseType</code></strong> - The stake must consist 100% of free-bet money. Real\nmoney cannot be mixed in.</p>\n<ul>\n<li><strong>isMustBeStakedAtOnce</strong> (boolean, required) - When <code>true</code>, the entire free-bet\nbalance must be wagered in a <strong>single</strong> bet (the player cannot split the\nbalance across multiple bets). When <code>false</code>, the player may place multiple bets\nuntil the balance is exhausted, subject to <code>maxAmountOfBets</code>.</li>\n</ul>\n</li>\n<li><p><strong><code>FreeBetPartialBalanceUseType</code></strong> - The stake may mix free-bet money with real\nmoney. Each bet's free-bet portion is bounded.</p>\n<ul>\n<li><strong>minValue</strong> (MoneyBag, optional) - Minimum free-bet amount per bet. <code>null</code> =\nno minimum.</li>\n<li><strong>maxValue</strong> (MoneyBag, optional) - Maximum free-bet amount per bet. <code>null</code> =\nno maximum.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"moneybag\"><code>MoneyBag</code></h3>\n<p>Shape — examples in this document use only the <code>system</code> amount in a single currency:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n</code></pre>\n<ul>\n<li><strong>system</strong> (<code>{amount, currency}</code>, required) - The amount in the bonus's currency.\nThe <code>amount</code> is a <strong>string</strong> (decimal with no implied scaling — the bonus engine\nstores monetary values in raw integer minor-unit form, e.g. <code>\"50000\"</code> = 500.00 TRY).</li>\n<li><strong>additional</strong> (array, required) - Per-currency overrides for cross-currency\nbonuses. When the player's currency matches an entry's <code>currency</code>, the entry's\n<code>amount</code> is used directly; otherwise the <code>system</code> amount is converted via the\noperator's currency-pair rates. Single-currency bonuses (the common case) emit\nan empty array, as in all examples in this document.</li>\n</ul>\n<h2 id=\"request-examples\">Request Examples</h2>\n<h3 id=\"mode-1--catalogue-lookup\">Mode 1 — Catalogue lookup</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"available\": true\n}\n</code></pre>\n<h3 id=\"mode-2--available-bonuses-for-a-specific-player\">Mode 2 — Available bonuses for a specific player</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n</code></pre>\n<h3 id=\"mode-3--registration-bonuses-only\">Mode 3 — Registration bonuses only</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n</code></pre>\n<h2 id=\"response-examples\">Response Examples</h2>\n<h3 id=\"successful-response-200-ok--internal-free-bet-minimal-sportsbook\">Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)</h3>\n<p>The faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n<strong>Demonstrates the unrestricted shape:</strong> <code>filters[0]</code> has every dimension <code>null</code> /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). <code>freeBetUseType</code> is <code>FreeBetAllBalanceUseType</code> with\n<code>isMustBeStakedAtOnce: true</code>, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n</code></pre>\n<h3 id=\"successful-response-200-ok--internal-free-bet-populated-sportsbook\">Successful Response (200 OK) — Internal Free Bet (populated sportsbook)</h3>\n<p>A 100 TRY free bet for <strong>Premier League pre-match singles and parlays</strong>.\n<strong>Demonstrates every populated dimension using real SportsbookSchema values:</strong></p>\n<ul>\n<li>Sport / category / tournament gating: <code>sportId</code> (Football),\n<code>categoryId</code> (England), <code>tournamentId</code> (Premier League).</li>\n<li>Three real <code>MarketType</code> values allow-listed:\n<code>[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]</code>.</li>\n<li><code>betTypes: [\"single\", \"parlay\"]</code> — uses real <code>BetHashType</code> JSON values\n(lowercase via Jackson <code>@JsonProperty</code>).</li>\n<li><code>live: false</code> — pre-match only.</li>\n<li><code>single</code> bets must have an odd ≥ <code>1.5</code>.</li>\n<li><code>parlay</code> bets must have total odds ≥ <code>3.0</code>, between <code>3</code> and <code>10</code> selections, every\nselection at min odd <code>1.2</code>, with at least one selection at min odd <code>1.3</code>.</li>\n<li>Stake band <code>25 TRY ≤ stake ≤ 100 TRY</code>, max win <code>1000 TRY</code>, max <code>5</code> bets.</li>\n<li>72-hour validity once activated.</li>\n<li><code>freeBetUseType</code> is <code>FreeBetPartialBalanceUseType</code> with the same <code>25-100 TRY</code> bounds\nper bet — meaning the player may combine free-bet money with real money on the\nsame stake.</li>\n<li><code>isAutoActivates: false</code> — the partner must call <code>activate-player-bonus</code> after\nclaim.</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n</code></pre>\n<h3 id=\"successful-response-200-ok--empty-result\">Successful Response (200 OK) — Empty result</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"bonuses\": []\n}\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li>Both <code>available</code> and <code>tag</code> omitted.</li>\n<li><code>tag</code> provided but not equal to <code>\"REGISTRATION\"</code> (case-insensitive).</li>\n<li>Malformed <code>brandId</code> (non-integer) or missing <code>Authorization</code>.</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---deserialization-error\">400 Bad Request - Deserialization Error</h3>\n<p>Occurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<p>Occurs in Mode 2 when the <code>externalUserId</code> cannot be resolved or registered\nautomatically.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n</code></pre>\n<h3 id=\"401-unauthorized---invalid-credentials\">401 Unauthorized - Invalid Credentials</h3>\n<p>Occurs when <code>Authorization</code> is missing, malformed, or does not match a known brand\ncredential.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n</code></pre>\n<h3 id=\"403-forbidden---ip-not-whitelisted\">403 Forbidden - IP not whitelisted</h3>\n<p>Occurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.</p>\n<p><strong>Example Error Response (HTML body, status 403):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-text\">IP &lt;client-ip&gt; is not presented in white list\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<p>Occurs when an unexpected server error happens.</p>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Sportsbook free-bet only.</strong> This integration is purpose-built for\n<code>INTERNAL_FREE_BET</code> bonuses on the sportsbook product\n(<code>InternalFreeBetSportsbookCriteria</code> payload). <code>winSize</code> is always <code>null</code>,\n<code>wagering</code> is always <code>null</code>. All limits and rules are encoded inside\n<code>bonusSize.rule.productRules[].criteria</code> and <code>bonusSize.rule.freeBetUseType</code>. Other\n<code>bonusType</code> values and non-sportsbook free-bet criteria may appear in the catalogue\nand should be filtered out client-side.</p>\n</li>\n<li><p><strong>Real schema values.</strong> <code>betRule.betTypes</code> uses the <strong><code>BetHashType</code></strong> enum with\nlowercase JSON values (<code>\"single\"</code>, <code>\"parlay\"</code>, <code>\"system\"</code>) — the <code>parlay</code> value is\nthe schema name for accumulator bets. <code>markets</code> uses the <strong><code>MarketType</code></strong> enum\nfrom the generated SportsbookSchema (lowercase names like <code>score_1x2</code>, <code>score_ou</code>,\n<code>score_both_to_score_yes_no</code>).</p>\n</li>\n<li><p><strong>Visibility flag handling.</strong> In Mode 1 (catalogue) the operator-side\n<code>\"Show For Players\"</code> visibility flag is ignored — partners see the full enabled\ncatalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n<code>isShownForPlayers: false</code> are hidden.</p>\n</li>\n<li><p><strong>Mode 2 player registration side-effect.</strong> When <code>externalUserId</code> is unknown to\nSumstats, the system attempts to register the player automatically before\nevaluating eligibility. Subsequent calls for the same <code>externalUserId</code> skip\nthis step. If automatic registration fails, the request fails with\n<code>INVALID_USER</code> (109).</p>\n</li>\n<li><p><strong>Polymorphic <code>__payloadKind</code> discriminator.</strong> All polymorphic objects\n(<code>bonusSize</code>, <code>criteria</code>, <code>freeBetUseType</code>, <code>bonusSize.amount</code>) carry a\n<code>__payloadKind</code> field containing the concrete payload kind. Partners must\ndiscriminate on this field — adding new payload kinds in the future is the\nstandard evolution path.</p>\n</li>\n<li><p><strong><code>MoneyBag.system</code> semantics.</strong> <code>system</code> carries the canonical amount in the\noperator's accounting currency. When the player's currency matches an entry in\n<code>additional</code>, that override is used directly; otherwise the system entry is\nconverted via the operator's currency-pair rates. Partners should prefer the\n<code>additional</code> entry matching the player's currency for display.</p>\n</li>\n<li><p><strong>Currencies and bonus selection.</strong> The <code>currencies</code> array on the bonus is the\nset of currencies the bonus supports. In Mode 2, only bonuses whose <code>currencies</code>\narray contains the player's currency are returned.</p>\n</li>\n<li><p><strong>Empty filter list semantics.</strong> <code>criteria.filters</code> is an array — an <strong>empty\narray</strong> means \"no narrowing\": the free bet may be staked on any sportsbook event.\n<strong>A non-empty filter list is OR'd:</strong> a stake is allowed when at least one filter\naccepts it.</p>\n</li>\n<li><p><strong>Empty-vs-null in <code>betRule</code>.</strong> <code>betRule.betTypes: []</code> and <code>betRule.markets: []</code>\nmean \"any\" (no restriction); <code>betRule.live: null</code> means \"any live mode\"; numeric /\ninteger fields use <code>null</code> for \"no restriction\". The semantics differ — empty array\non <code>betTypes</code> / <code>markets</code>, <code>null</code> on the rest.</p>\n</li>\n<li><p><strong><code>isAutoActivates</code> impact on the claim flow.</strong> When <code>isAutoActivates: true</code>,\ncalling <code>claim-bonus-for-player</code> immediately moves the player bonus to\n<code>IN_PROGRESS</code>. When <code>false</code>, the partner must call <code>activate-player-bonus</code> within\n<code>timeForActivationInHours</code> hours.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Basic base64(username:password)\nContent-Type: application/json\n</code></pre>\n<p>Use the <code>brandId</code> body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request <code>brandId</code> matches.</p>\n","urlObject":{"path":["external-casino-client","v1","bonus","find-available-bonuses"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"317f74c6-9496-4ffd-90d1-8c8911bec77b","name":"success — Internal Free Bet (minimal sportsbook)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"# Endpoint for Finding Available Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-available-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet bonuses** currently offered\nby the operator. Three usage modes are selected via the request body fields:\n\n- **Mode 1 — All available bonuses (catalogue).** `available: true`, `externalUserId`\n  omitted. Returns all enabled, in-activity-window bonuses. The operator-side\n  `\"Show For Players\"` visibility flag is **ignored** in this mode — the full catalogue\n  is exposed so the partner can plan campaigns.\n- **Mode 2 — Available bonuses for a specific player.** `available: true`,\n  `externalUserId` set. Returns only the bonuses available *for that player*: per-player\n  limits, claim eligibility rules and the operator-side visibility flag are honoured,\n  and bonuses already claimed/active for the player are excluded. If the external\n  player is unknown to Sumstats, the system attempts to register them automatically\n  before evaluating eligibility.\n- **Mode 3 — Registration bonuses only.** `tag: \"REGISTRATION\"` (with or without\n  `available`). Returns the subset of bonuses tagged for new-player registration flows.\n\nThe response is **not paginated** — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(`bonusSize.__payloadKind = \"FreeBetSize\"`) describing the substantive offer; the\npartner is expected to discriminate on `__payloadKind` for nested polymorphic objects\n(`criteria`, `freeBetUseType`, `bonusSize.amount`).\n\n> **Scope.** This integration is purpose-built for `INTERNAL_FREE_BET` bonuses on the\n> sportsbook product (`InternalFreeBetSportsbookCriteria` payload). Other bonus types\n> (`CUSTOM`, `FIRST_DEPOSIT`, `EXTERNAL_FREE_BET`, `EXTERNAL_FREE_SPINS_WITH_WAGERING`,\n> `INTERNAL_FREE_SPINS_WITH_WAGERING`, `CASHBACK`) and non-sportsbook free-bet\n> criteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n> `bonusType: \"INTERNAL_FREE_BET\"` with\n> `bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"`\n> client-side.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the brand\n  encoded in the HTTP Basic credentials. Used together with `Authorization` for\n  credential lookup.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only — partners on the new contract must send `brandId`.\n\n- **available** (boolean, optional) - When `true` activates Mode 1 or Mode 2 selection.\n  When omitted, `tag` must be set, otherwise the request is rejected with\n  `BAD_REQUEST`.\n\n- **externalUserId** (string, optional) - External player id in the operator system.\n  When set, switches the call to Mode 2 (per-player filtering). If the player is\n  unknown to Sumstats, the system attempts to register them automatically.\n\n- **tag** (string, optional) - When set, must be `\"REGISTRATION\"` (case-insensitive)\n  and switches the call to Mode 3. Any other value is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **bonuses** (array of objects, required) - List of bonus objects matching the query.\n  Empty list when nothing matches. The partner-facing slim shape drops\n  internal/operational fields (`descriptionTitle`, `descriptionBonusRules`,\n  `fullTermsAndConditions`, `descriptionFiles`, `isShownForPlayers`, `bonusTags`,\n  `shareLimitsId`, `eligibilityClaimRulesCompletionInfo`, `notSatisfiedMatchResults`,\n  `satisfiedMatchResults`, `operatorId`, `ruleIds`, `removedAt`, `updatedAt`,\n  `playerGroupIds`, `bonusOverridableFeatures`).\n\n  Each bonus object has the structure documented under **Bonus Fields** below.\n\n### Bonus Fields\n\nThe slim partner-facing bonus shape. Field-by-field semantics:\n\n- **id** (string, required) - Bonus identifier in **UUID v7** format. This is the\n  *catalogue* id of the bonus configuration, not a per-player id. Pass to\n  `claim-bonus-for-player`, `activate-player-bonus`, `cancel-player-bonus`. Stable\n  across partner calls — repeated `find-available-bonuses` requests return the same\n  `id` for the same operator-configured bonus until the operator deletes the\n  configuration.\n\n- **name** (array of `{locale, translate}`, required) - Localised bonus names. Each\n  entry binds a `locale` (BCP-47 / ICU locale code, e.g. `en_US`, `de_DE`) to\n  the human-readable bonus name in that locale. Partners should pick the entry\n  matching the player's locale; when no exact match exists, fall back to `en_US` or\n  the first entry. Bonuses are guaranteed to have **at least one** translation\n  (typically `en_US`).\n\n- **bonusType** (enum, required) - High-level bonus kind. **For this integration's\n  contract, the relevant value is `INTERNAL_FREE_BET`.** Drives which payload shapes\n  appear inside `bonusSize`. Other types may appear in the catalogue but are out of\n  scope — partners should filter the response to `bonusType: \"INTERNAL_FREE_BET\"`\n  client-side.\n\n- **status** (enum, required) - Lifecycle status of the bonus on the operator side.\n  Possible values:\n\n  - `NOT_STARTED` - Created and saved but the activity window has not started yet.\n  - `SCHEDULED` - Inside the configured activity window but the bonus is scheduled to go active at a later point.\n  - `ACTIVE` - Enabled and inside the activity window. Only `ACTIVE` bonuses can be claimed.\n  - `DISABLED` - Operator switched the bonus off from the admin panel.\n  - `EXPIRED` - Activity window has passed.\n  - `REMOVED` - Operator deleted the bonus configuration. Catalogue audits only — not claimable.\n\n  Only `ACTIVE` bonuses can be claimed — `find-available-bonuses` does not return\n  non-`ACTIVE` bonuses by default; the field is informational for catalogue audits.\n\n- **enabled** (boolean, required) - `false` when the operator has explicitly disabled\n  the bonus from the admin panel. A bonus with `status: ACTIVE` and `enabled: false`\n  is unavailable for new claims and will not appear in Mode 2 (per-player) responses.\n  Mode 1 (catalogue) responses include disabled bonuses for partner audit purposes.\n\n- **promotionCode** (string, optional) - Operator-issued promotion code (e.g.\n  `\"500TRYFREEBET\"`, `\"EPL100\"`). When set, the bonus is gated by the code on the\n  player-facing surface — players can only claim it through a promo-code flow.\n  `null` when the bonus is freely claimable. **Partners using this integration claim\n  by `bonusId` directly and bypass the promo-code gate**, but the field is exposed\n  so partners can mirror operator-side promo flows on their UI.\n\n- **activityTime** (object, optional) - Activity window. `null` means always on\n  (no time gate). The shape mirrors the internal `ActivityTime` record — at most\n  one of `timePeriod` / `timeSchedule` is populated:\n\n  - **timePeriod** (object, optional) - Continuous activity window.\n    - **timeRange** (object, required) - Half-open period.\n      - **from** (long, optional) - Start of the window in **epoch millis (UTC)**.\n        `null` means open-ended start.\n      - **to** (long, optional) - End of the window in **epoch millis (UTC)**.\n        `null` means open-ended end.\n    - **isShownBeforePeriod** (boolean, required) - Whether the bonus is exposed\n      to players before `timeRange.from`.\n    - **isShownAfterPeriod** (boolean, required) - Whether the bonus is exposed\n      after `timeRange.to`.\n    - **shownBeforePeriodMinutes** (long, optional) - How long before\n      `timeRange.from` the bonus becomes visible.\n    - **shownAfterPeriodMinutes** (long, optional) - How long after\n      `timeRange.to` the bonus remains visible.\n  - **timeSchedule** (object, optional) - Recurring activity schedule.\n    Polymorphic on `__payloadKind`:\n    - `HoursOfDayTimeSchedule` — recurring hours-of-day periods (`periods`).\n    - `DaysOfWeekTimeSchedule` — recurring per-day-of-week periods\n      (`periodsByDay`).\n    - `DaysOfMonthTimeSchedule` — recurring per-day-of-month periods\n      (`periodsByDay`).\n\n    `null` when activity is window-only.\n\n  Outside the window the bonus is unclaimable (Sumstats responds with\n  `BONUS_NOT_AVAILABLE` (303) on claim).\n\n- **timeForActivationInHours** (integer, optional) - Hours after claim during which\n  the player must activate the bonus (i.e. how long the `CLAIMED → IN_PROGRESS`\n  transition is allowed). `null` = unlimited (the player bonus stays in `CLAIMED`\n  until activation or manual cancel). Used by Sumstats to compute `expiredOnClaimAt`\n  on the resulting player bonus. Example: `168` means the player has seven days to\n  activate.\n\n- **currencies** (array of strings, required) - Currencies the bonus supports\n  (ISO 4217 codes — `TRY`, `EUR`, `USD`, …). The bonus can only be claimed by players\n  whose account currency is in this set. In Mode 2, only bonuses whose `currencies`\n  array contains the player's currency are returned. Empty array indicates a\n  misconfiguration on the operator side.\n\n- **isAutoActivates** (boolean, required) - When `true`, the bonus auto-activates on\n  claim — partners do **not** need to call `activate-player-bonus`. The\n  `claim-bonus-for-player` response carries `status: \"IN_PROGRESS\"` and a populated\n  `activatedAt`. When `false`, the partner must explicitly call `activate-player-bonus`\n  within `timeForActivationInHours` hours, or the player bonus expires.\n\n- **bonusSize** (object, required) - Substantive offer payload describing the\n  free-bet rule and amount. **For `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind`\n  is always `\"FreeBetSize\"`.** See **FreeBetSize** below.\n\n- **winSize** (object, optional) - Cap on potential winnings. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — the substantive limits are encoded inside the\n  free-bet criteria (`bonusSize.rule.productRules[].criteria.maxWinAllowed`).\n\n- **wagering** (object, optional) - Wagering rules. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — free bets do not have a turnover requirement; the\n  free bet either wins, loses, or expires per the criteria rules.\n\n### `bonusSize` — FreeBetSize\n\nFor `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind = \"FreeBetSize\"`. The\n`FreeBetSize` payload has two top-level fields:\n\n- **rule** (object, required) - The free-bet rule — defines per-product criteria,\n  free-bet use type, and validity. See **FreeBetRule** below.\n- **amount** (object, optional) - Total monetary value handed to the player as a\n  free-bet balance when the bonus is activated. Polymorphic on `__payloadKind`. Two\n  practical kinds for free bets:\n\n  - **MonetarySize** - Fixed amount.\n\n    - **money** (MoneyBag, required) - The free-bet balance. See **MoneyBag** below.\n\n  - **PercentageSize** - Percentage of a baseline (rare for free bets).\n\n    - **percentage** (number, required) - Percentage value, e.g. `100.0` = 100%.\n    - **maxAmount** (MoneyBag, optional) - Upper cap on the resulting balance.\n    - **minAmount** (MoneyBag, optional) - Lower floor on the resulting balance.\n\n### `bonusSize.rule` — FreeBetRule\n\n**Object:**\n\n- **productRules** (array of `FreeBetProductRule`, required, length ≥ 1) - Per-product\n  free-bet criteria. **For sportsbook free bets there is a single entry with\n  `product: \"SPORTS\"`.**\n\n  Each `FreeBetProductRule` has:\n\n  - **note** (array of `{locale, translate}`, optional) - Operator-supplied note\n    describing the rule, localised. `null` when no note was set.\n  - **title** (array of `{locale, translate}`, optional) - Operator-supplied title\n    for the rule, localised. `null` when no title was set.\n  - **product** (string, required) - For this integration's scope, always `\"SPORTS\"`.\n  - **criteria** (object, required) - Per-product limit rules. Polymorphic on\n    `__payloadKind`. **For sportsbook free bets,\n    `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.** See\n    **InternalFreeBetSportsbookCriteria** below.\n\n- **validityInHours** (integer, required) - Lifetime of the *activated* bonus, in\n  hours. `0` = unlimited (the bonus runs until the free-bet balance is exhausted,\n  the bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\n  Used by Sumstats to compute `expiredAt` on the activated player bonus.\n\n- **note** (array of `{locale, translate}`, optional) - Free-form operator note for\n  the rule as a whole, localised. `null` when no note was set.\n\n- **freeBetUseType** (object, required) - How the free-bet money composes the\n  player's stake. Polymorphic on `__payloadKind`. See **FreeBetUseType union** below.\n\n### `criteria` — InternalFreeBetSportsbookCriteria\n\nFor sportsbook free bets, `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.\nTop-level fields:\n\n- **filters** (array of `InternalFreeBetSportsbookFilter`, required) - Filter list\n  narrowing where the free bet may be staked. **An empty filter list means \"no\n  narrowing\"** (the free bet may be staked on any sportsbook event). Multiple filters\n  are OR'd: a stake is allowed if **at least one** filter accepts it. See\n  **InternalFreeBetSportsbookFilter** below.\n\n- **minValue** (MoneyBag, optional) - Minimum bet stake required. `null` = no\n  minimum. Stakes below this are rejected by the bet placement engine.\n\n- **maxValue** (MoneyBag, optional) - Maximum bet stake allowed. `null` = no\n  maximum. Stakes above this are rejected.\n\n- **maxWinAllowed** (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\n  single free-bet stake are capped at this amount. `null` = no cap (free bet pays\n  out the full computed winnings).\n\n- **maxAmountOfBets** (integer, optional) - Maximum number of bets the player may\n  place using the free-bet balance. `null` = unlimited (the bonus runs until the\n  free-bet balance is exhausted or expires). Once the limit is hit, the bonus\n  transitions to `COMPLETED` automatically.\n\n#### `filters[]` — InternalFreeBetSportsbookFilter\n\nNarrows the events on which the free bet may be staked. **All scalar fields are\nnullable; `null` means \"no restriction on this dimension\".** The filter accepts a\nstake when *every* set field matches the stake's event metadata:\n\n- **sportId** (string, optional) - Restrict to a specific sport (UUID, operator-defined\n  — e.g. football, basketball, tennis). `null` = any sport.\n\n- **categoryId** (string, optional) - Restrict to a category — typically a country /\n  region inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n  `null` = any category.\n\n- **tournamentId** (string, optional) - Restrict to a tournament inside a category\n  (UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). `null` = any\n  tournament.\n\n- **eventId** (string, optional) - Restrict to a single event / match (UUID,\n  operator-defined). `null` = any event.\n\n- **markets** (array of `MarketType`, required) - Allow-listed market identifiers\n  from the generated `MarketType` enum (lowercase enum names from the SportsbookSchema).\n  Examples: `score_1x2`, `score_ou`, `score_dc`, `score_both_to_score_yes_no`,\n  `score_ht_ft`, `score_winning_margin`, `score_exact_number`, `corner_1x2`,\n  `yellow_card_1x2`. **Empty array means any market.**\n\n- **betRule** (object, optional) - Bet-shape restrictions. **All `betRule` fields\n  are nullable; `null` (or empty for set-typed fields) means \"no restriction on this\n  dimension\".** A stake is accepted when every set field matches.\n\n  - **betTypes** (array of `BetHashType`, required) - Allowed bet types from the\n    `BetHashType` enum. The JSON wire form is **lowercase** (set by Jackson\n    `@JsonProperty` on the enum). Possible values:\n\n    - `single` - A single selection bet.\n    - `parlay` - Accumulator bet (multiple selections combined; all must win).\n      The `accumulator*` betRule fields below apply only to this bet type.\n    - `system` - System bet (combinations of accumulators).\n\n    **Empty array means any bet type.**\n\n  - **live** (boolean, optional) - `true` = live betting only, `false` = pre-match\n    only, `null` = both allowed.\n  - **singleMinOdd** (number, optional) - Minimum odd for `single` bets. Ignored\n    for non-single bet types. Applied to the bet's single odd at placement time.\n  - **accumulatorTotalOdds** (number, optional) - Minimum total odds for a `parlay`\n    (the product of all selection odds). Ignored for non-`parlay` bet types.\n  - **accumulatorAtLeastOdd** (number, optional) - At least one selection in the\n    `parlay` must have an odd ≥ this value. Combined with\n    `accumulatorMinOddPerSelection` for fine-grained control.\n  - **accumulatorMinNumberOfSelections** (integer, optional) - Minimum number of\n    legs (selections) in the `parlay`.\n  - **accumulatorMaxNumberOfSelections** (integer, optional) - Maximum number of\n    legs in the `parlay`.\n  - **accumulatorMinOddPerSelection** (number, optional) - Minimum odd that\n    **every** selection in the `parlay` must meet.\n\n### `freeBetUseType` — FreeBetUseType union\n\nDiscriminated by `__payloadKind`. Two concrete kinds:\n\n- **`FreeBetAllBalanceUseType`** - The stake must consist 100% of free-bet money. Real\n  money cannot be mixed in.\n\n  - **isMustBeStakedAtOnce** (boolean, required) - When `true`, the entire free-bet\n    balance must be wagered in a **single** bet (the player cannot split the\n    balance across multiple bets). When `false`, the player may place multiple bets\n    until the balance is exhausted, subject to `maxAmountOfBets`.\n\n- **`FreeBetPartialBalanceUseType`** - The stake may mix free-bet money with real\n  money. Each bet's free-bet portion is bounded.\n\n  - **minValue** (MoneyBag, optional) - Minimum free-bet amount per bet. `null` =\n    no minimum.\n  - **maxValue** (MoneyBag, optional) - Maximum free-bet amount per bet. `null` =\n    no maximum.\n\n### `MoneyBag`\n\nShape — examples in this document use only the `system` amount in a single currency:\n\n```json\n{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n```\n\n- **system** (`{amount, currency}`, required) - The amount in the bonus's currency.\n  The `amount` is a **string** (decimal with no implied scaling — the bonus engine\n  stores monetary values in raw integer minor-unit form, e.g. `\"50000\"` = 500.00 TRY).\n- **additional** (array, required) - Per-currency overrides for cross-currency\n  bonuses. When the player's currency matches an entry's `currency`, the entry's\n  `amount` is used directly; otherwise the `system` amount is converted via the\n  operator's currency-pair rates. Single-currency bonuses (the common case) emit\n  an empty array, as in all examples in this document.\n\n## Request Examples\n\n### Mode 1 — Catalogue lookup\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true\n}\n```\n\n### Mode 2 — Available bonuses for a specific player\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n```\n\n### Mode 3 — Registration bonuses only\n\n```json\n{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)\n\nThe faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n**Demonstrates the unrestricted shape:** `filters[0]` has every dimension `null` /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). `freeBetUseType` is `FreeBetAllBalanceUseType` with\n`isMustBeStakedAtOnce: true`, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Internal Free Bet (populated sportsbook)\n\nA 100 TRY free bet for **Premier League pre-match singles and parlays**.\n**Demonstrates every populated dimension using real SportsbookSchema values:**\n\n- Sport / category / tournament gating: `sportId` (Football),\n  `categoryId` (England), `tournamentId` (Premier League).\n- Three real `MarketType` values allow-listed:\n  `[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]`.\n- `betTypes: [\"single\", \"parlay\"]` — uses real `BetHashType` JSON values\n  (lowercase via Jackson `@JsonProperty`).\n- `live: false` — pre-match only.\n- `single` bets must have an odd ≥ `1.5`.\n- `parlay` bets must have total odds ≥ `3.0`, between `3` and `10` selections, every\n  selection at min odd `1.2`, with at least one selection at min odd `1.3`.\n- Stake band `25 TRY ≤ stake ≤ 100 TRY`, max win `1000 TRY`, max `5` bets.\n- 72-hour validity once activated.\n- `freeBetUseType` is `FreeBetPartialBalanceUseType` with the same `25-100 TRY` bounds\n  per bet — meaning the player may combine free-bet money with real money on the\n  same stake.\n- `isAutoActivates: false` — the partner must call `activate-player-bonus` after\n  claim.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty result\n\n```json\n{\n    \"bonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- Both `available` and `tag` omitted.\n- `tag` provided but not equal to `\"REGISTRATION\"` (case-insensitive).\n- Malformed `brandId` (non-integer) or missing `Authorization`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\nOccurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nOccurs in Mode 2 when the `externalUserId` cannot be resolved or registered\nautomatically.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\nOccurs when `Authorization` is missing, malformed, or does not match a known brand\ncredential.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 403 Forbidden - IP not whitelisted\n\nOccurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.\n\n**Example Error Response (HTML body, status 403):**\n\n```text\nIP <client-ip> is not presented in white list\n```\n\n### 500 Internal Server Error - Unknown Error\n\nOccurs when an unexpected server error happens.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Sportsbook free-bet only.** This integration is purpose-built for\n   `INTERNAL_FREE_BET` bonuses on the sportsbook product\n   (`InternalFreeBetSportsbookCriteria` payload). `winSize` is always `null`,\n   `wagering` is always `null`. All limits and rules are encoded inside\n   `bonusSize.rule.productRules[].criteria` and `bonusSize.rule.freeBetUseType`. Other\n   `bonusType` values and non-sportsbook free-bet criteria may appear in the catalogue\n   and should be filtered out client-side.\n\n2. **Real schema values.** `betRule.betTypes` uses the **`BetHashType`** enum with\n   lowercase JSON values (`\"single\"`, `\"parlay\"`, `\"system\"`) — the `parlay` value is\n   the schema name for accumulator bets. `markets` uses the **`MarketType`** enum\n   from the generated SportsbookSchema (lowercase names like `score_1x2`, `score_ou`,\n   `score_both_to_score_yes_no`).\n\n3. **Visibility flag handling.** In Mode 1 (catalogue) the operator-side\n   `\"Show For Players\"` visibility flag is ignored — partners see the full enabled\n   catalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n   `isShownForPlayers: false` are hidden.\n\n4. **Mode 2 player registration side-effect.** When `externalUserId` is unknown to\n   Sumstats, the system attempts to register the player automatically before\n   evaluating eligibility. Subsequent calls for the same `externalUserId` skip\n   this step. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n5. **Polymorphic `__payloadKind` discriminator.** All polymorphic objects\n   (`bonusSize`, `criteria`, `freeBetUseType`, `bonusSize.amount`) carry a\n   `__payloadKind` field containing the concrete payload kind. Partners must\n   discriminate on this field — adding new payload kinds in the future is the\n   standard evolution path.\n\n6. **`MoneyBag.system` semantics.** `system` carries the canonical amount in the\n   operator's accounting currency. When the player's currency matches an entry in\n   `additional`, that override is used directly; otherwise the system entry is\n   converted via the operator's currency-pair rates. Partners should prefer the\n   `additional` entry matching the player's currency for display.\n\n7. **Currencies and bonus selection.** The `currencies` array on the bonus is the\n   set of currencies the bonus supports. In Mode 2, only bonuses whose `currencies`\n   array contains the player's currency are returned.\n\n8. **Empty filter list semantics.** `criteria.filters` is an array — an **empty\n   array** means \"no narrowing\": the free bet may be staked on any sportsbook event.\n   **A non-empty filter list is OR'd:** a stake is allowed when at least one filter\n   accepts it.\n\n9. **Empty-vs-null in `betRule`.** `betRule.betTypes: []` and `betRule.markets: []`\n   mean \"any\" (no restriction); `betRule.live: null` means \"any live mode\"; numeric /\n   integer fields use `null` for \"no restriction\". The semantics differ — empty array\n   on `betTypes` / `markets`, `null` on the rest.\n\n10. **`isAutoActivates` impact on the claim flow.** When `isAutoActivates: true`,\n    calling `claim-bonus-for-player` immediately moves the player bonus to\n    `IN_PROGRESS`. When `false`, the partner must call `activate-player-bonus` within\n    `timeForActivationInHours` hours.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}"},{"id":"a8875a64-a539-4ef9-975e-b0740cb0242e","name":"success — Internal Free Bet (populated sportsbook)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"# Endpoint for Finding Available Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-available-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet bonuses** currently offered\nby the operator. Three usage modes are selected via the request body fields:\n\n- **Mode 1 — All available bonuses (catalogue).** `available: true`, `externalUserId`\n  omitted. Returns all enabled, in-activity-window bonuses. The operator-side\n  `\"Show For Players\"` visibility flag is **ignored** in this mode — the full catalogue\n  is exposed so the partner can plan campaigns.\n- **Mode 2 — Available bonuses for a specific player.** `available: true`,\n  `externalUserId` set. Returns only the bonuses available *for that player*: per-player\n  limits, claim eligibility rules and the operator-side visibility flag are honoured,\n  and bonuses already claimed/active for the player are excluded. If the external\n  player is unknown to Sumstats, the system attempts to register them automatically\n  before evaluating eligibility.\n- **Mode 3 — Registration bonuses only.** `tag: \"REGISTRATION\"` (with or without\n  `available`). Returns the subset of bonuses tagged for new-player registration flows.\n\nThe response is **not paginated** — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(`bonusSize.__payloadKind = \"FreeBetSize\"`) describing the substantive offer; the\npartner is expected to discriminate on `__payloadKind` for nested polymorphic objects\n(`criteria`, `freeBetUseType`, `bonusSize.amount`).\n\n> **Scope.** This integration is purpose-built for `INTERNAL_FREE_BET` bonuses on the\n> sportsbook product (`InternalFreeBetSportsbookCriteria` payload). Other bonus types\n> (`CUSTOM`, `FIRST_DEPOSIT`, `EXTERNAL_FREE_BET`, `EXTERNAL_FREE_SPINS_WITH_WAGERING`,\n> `INTERNAL_FREE_SPINS_WITH_WAGERING`, `CASHBACK`) and non-sportsbook free-bet\n> criteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n> `bonusType: \"INTERNAL_FREE_BET\"` with\n> `bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"`\n> client-side.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the brand\n  encoded in the HTTP Basic credentials. Used together with `Authorization` for\n  credential lookup.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only — partners on the new contract must send `brandId`.\n\n- **available** (boolean, optional) - When `true` activates Mode 1 or Mode 2 selection.\n  When omitted, `tag` must be set, otherwise the request is rejected with\n  `BAD_REQUEST`.\n\n- **externalUserId** (string, optional) - External player id in the operator system.\n  When set, switches the call to Mode 2 (per-player filtering). If the player is\n  unknown to Sumstats, the system attempts to register them automatically.\n\n- **tag** (string, optional) - When set, must be `\"REGISTRATION\"` (case-insensitive)\n  and switches the call to Mode 3. Any other value is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **bonuses** (array of objects, required) - List of bonus objects matching the query.\n  Empty list when nothing matches. The partner-facing slim shape drops\n  internal/operational fields (`descriptionTitle`, `descriptionBonusRules`,\n  `fullTermsAndConditions`, `descriptionFiles`, `isShownForPlayers`, `bonusTags`,\n  `shareLimitsId`, `eligibilityClaimRulesCompletionInfo`, `notSatisfiedMatchResults`,\n  `satisfiedMatchResults`, `operatorId`, `ruleIds`, `removedAt`, `updatedAt`,\n  `playerGroupIds`, `bonusOverridableFeatures`).\n\n  Each bonus object has the structure documented under **Bonus Fields** below.\n\n### Bonus Fields\n\nThe slim partner-facing bonus shape. Field-by-field semantics:\n\n- **id** (string, required) - Bonus identifier in **UUID v7** format. This is the\n  *catalogue* id of the bonus configuration, not a per-player id. Pass to\n  `claim-bonus-for-player`, `activate-player-bonus`, `cancel-player-bonus`. Stable\n  across partner calls — repeated `find-available-bonuses` requests return the same\n  `id` for the same operator-configured bonus until the operator deletes the\n  configuration.\n\n- **name** (array of `{locale, translate}`, required) - Localised bonus names. Each\n  entry binds a `locale` (BCP-47 / ICU locale code, e.g. `en_US`, `de_DE`) to\n  the human-readable bonus name in that locale. Partners should pick the entry\n  matching the player's locale; when no exact match exists, fall back to `en_US` or\n  the first entry. Bonuses are guaranteed to have **at least one** translation\n  (typically `en_US`).\n\n- **bonusType** (enum, required) - High-level bonus kind. **For this integration's\n  contract, the relevant value is `INTERNAL_FREE_BET`.** Drives which payload shapes\n  appear inside `bonusSize`. Other types may appear in the catalogue but are out of\n  scope — partners should filter the response to `bonusType: \"INTERNAL_FREE_BET\"`\n  client-side.\n\n- **status** (enum, required) - Lifecycle status of the bonus on the operator side.\n  Possible values:\n\n  - `NOT_STARTED` - Created and saved but the activity window has not started yet.\n  - `SCHEDULED` - Inside the configured activity window but the bonus is scheduled to go active at a later point.\n  - `ACTIVE` - Enabled and inside the activity window. Only `ACTIVE` bonuses can be claimed.\n  - `DISABLED` - Operator switched the bonus off from the admin panel.\n  - `EXPIRED` - Activity window has passed.\n  - `REMOVED` - Operator deleted the bonus configuration. Catalogue audits only — not claimable.\n\n  Only `ACTIVE` bonuses can be claimed — `find-available-bonuses` does not return\n  non-`ACTIVE` bonuses by default; the field is informational for catalogue audits.\n\n- **enabled** (boolean, required) - `false` when the operator has explicitly disabled\n  the bonus from the admin panel. A bonus with `status: ACTIVE` and `enabled: false`\n  is unavailable for new claims and will not appear in Mode 2 (per-player) responses.\n  Mode 1 (catalogue) responses include disabled bonuses for partner audit purposes.\n\n- **promotionCode** (string, optional) - Operator-issued promotion code (e.g.\n  `\"500TRYFREEBET\"`, `\"EPL100\"`). When set, the bonus is gated by the code on the\n  player-facing surface — players can only claim it through a promo-code flow.\n  `null` when the bonus is freely claimable. **Partners using this integration claim\n  by `bonusId` directly and bypass the promo-code gate**, but the field is exposed\n  so partners can mirror operator-side promo flows on their UI.\n\n- **activityTime** (object, optional) - Activity window. `null` means always on\n  (no time gate). The shape mirrors the internal `ActivityTime` record — at most\n  one of `timePeriod` / `timeSchedule` is populated:\n\n  - **timePeriod** (object, optional) - Continuous activity window.\n    - **timeRange** (object, required) - Half-open period.\n      - **from** (long, optional) - Start of the window in **epoch millis (UTC)**.\n        `null` means open-ended start.\n      - **to** (long, optional) - End of the window in **epoch millis (UTC)**.\n        `null` means open-ended end.\n    - **isShownBeforePeriod** (boolean, required) - Whether the bonus is exposed\n      to players before `timeRange.from`.\n    - **isShownAfterPeriod** (boolean, required) - Whether the bonus is exposed\n      after `timeRange.to`.\n    - **shownBeforePeriodMinutes** (long, optional) - How long before\n      `timeRange.from` the bonus becomes visible.\n    - **shownAfterPeriodMinutes** (long, optional) - How long after\n      `timeRange.to` the bonus remains visible.\n  - **timeSchedule** (object, optional) - Recurring activity schedule.\n    Polymorphic on `__payloadKind`:\n    - `HoursOfDayTimeSchedule` — recurring hours-of-day periods (`periods`).\n    - `DaysOfWeekTimeSchedule` — recurring per-day-of-week periods\n      (`periodsByDay`).\n    - `DaysOfMonthTimeSchedule` — recurring per-day-of-month periods\n      (`periodsByDay`).\n\n    `null` when activity is window-only.\n\n  Outside the window the bonus is unclaimable (Sumstats responds with\n  `BONUS_NOT_AVAILABLE` (303) on claim).\n\n- **timeForActivationInHours** (integer, optional) - Hours after claim during which\n  the player must activate the bonus (i.e. how long the `CLAIMED → IN_PROGRESS`\n  transition is allowed). `null` = unlimited (the player bonus stays in `CLAIMED`\n  until activation or manual cancel). Used by Sumstats to compute `expiredOnClaimAt`\n  on the resulting player bonus. Example: `168` means the player has seven days to\n  activate.\n\n- **currencies** (array of strings, required) - Currencies the bonus supports\n  (ISO 4217 codes — `TRY`, `EUR`, `USD`, …). The bonus can only be claimed by players\n  whose account currency is in this set. In Mode 2, only bonuses whose `currencies`\n  array contains the player's currency are returned. Empty array indicates a\n  misconfiguration on the operator side.\n\n- **isAutoActivates** (boolean, required) - When `true`, the bonus auto-activates on\n  claim — partners do **not** need to call `activate-player-bonus`. The\n  `claim-bonus-for-player` response carries `status: \"IN_PROGRESS\"` and a populated\n  `activatedAt`. When `false`, the partner must explicitly call `activate-player-bonus`\n  within `timeForActivationInHours` hours, or the player bonus expires.\n\n- **bonusSize** (object, required) - Substantive offer payload describing the\n  free-bet rule and amount. **For `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind`\n  is always `\"FreeBetSize\"`.** See **FreeBetSize** below.\n\n- **winSize** (object, optional) - Cap on potential winnings. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — the substantive limits are encoded inside the\n  free-bet criteria (`bonusSize.rule.productRules[].criteria.maxWinAllowed`).\n\n- **wagering** (object, optional) - Wagering rules. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — free bets do not have a turnover requirement; the\n  free bet either wins, loses, or expires per the criteria rules.\n\n### `bonusSize` — FreeBetSize\n\nFor `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind = \"FreeBetSize\"`. The\n`FreeBetSize` payload has two top-level fields:\n\n- **rule** (object, required) - The free-bet rule — defines per-product criteria,\n  free-bet use type, and validity. See **FreeBetRule** below.\n- **amount** (object, optional) - Total monetary value handed to the player as a\n  free-bet balance when the bonus is activated. Polymorphic on `__payloadKind`. Two\n  practical kinds for free bets:\n\n  - **MonetarySize** - Fixed amount.\n\n    - **money** (MoneyBag, required) - The free-bet balance. See **MoneyBag** below.\n\n  - **PercentageSize** - Percentage of a baseline (rare for free bets).\n\n    - **percentage** (number, required) - Percentage value, e.g. `100.0` = 100%.\n    - **maxAmount** (MoneyBag, optional) - Upper cap on the resulting balance.\n    - **minAmount** (MoneyBag, optional) - Lower floor on the resulting balance.\n\n### `bonusSize.rule` — FreeBetRule\n\n**Object:**\n\n- **productRules** (array of `FreeBetProductRule`, required, length ≥ 1) - Per-product\n  free-bet criteria. **For sportsbook free bets there is a single entry with\n  `product: \"SPORTS\"`.**\n\n  Each `FreeBetProductRule` has:\n\n  - **note** (array of `{locale, translate}`, optional) - Operator-supplied note\n    describing the rule, localised. `null` when no note was set.\n  - **title** (array of `{locale, translate}`, optional) - Operator-supplied title\n    for the rule, localised. `null` when no title was set.\n  - **product** (string, required) - For this integration's scope, always `\"SPORTS\"`.\n  - **criteria** (object, required) - Per-product limit rules. Polymorphic on\n    `__payloadKind`. **For sportsbook free bets,\n    `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.** See\n    **InternalFreeBetSportsbookCriteria** below.\n\n- **validityInHours** (integer, required) - Lifetime of the *activated* bonus, in\n  hours. `0` = unlimited (the bonus runs until the free-bet balance is exhausted,\n  the bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\n  Used by Sumstats to compute `expiredAt` on the activated player bonus.\n\n- **note** (array of `{locale, translate}`, optional) - Free-form operator note for\n  the rule as a whole, localised. `null` when no note was set.\n\n- **freeBetUseType** (object, required) - How the free-bet money composes the\n  player's stake. Polymorphic on `__payloadKind`. See **FreeBetUseType union** below.\n\n### `criteria` — InternalFreeBetSportsbookCriteria\n\nFor sportsbook free bets, `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.\nTop-level fields:\n\n- **filters** (array of `InternalFreeBetSportsbookFilter`, required) - Filter list\n  narrowing where the free bet may be staked. **An empty filter list means \"no\n  narrowing\"** (the free bet may be staked on any sportsbook event). Multiple filters\n  are OR'd: a stake is allowed if **at least one** filter accepts it. See\n  **InternalFreeBetSportsbookFilter** below.\n\n- **minValue** (MoneyBag, optional) - Minimum bet stake required. `null` = no\n  minimum. Stakes below this are rejected by the bet placement engine.\n\n- **maxValue** (MoneyBag, optional) - Maximum bet stake allowed. `null` = no\n  maximum. Stakes above this are rejected.\n\n- **maxWinAllowed** (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\n  single free-bet stake are capped at this amount. `null` = no cap (free bet pays\n  out the full computed winnings).\n\n- **maxAmountOfBets** (integer, optional) - Maximum number of bets the player may\n  place using the free-bet balance. `null` = unlimited (the bonus runs until the\n  free-bet balance is exhausted or expires). Once the limit is hit, the bonus\n  transitions to `COMPLETED` automatically.\n\n#### `filters[]` — InternalFreeBetSportsbookFilter\n\nNarrows the events on which the free bet may be staked. **All scalar fields are\nnullable; `null` means \"no restriction on this dimension\".** The filter accepts a\nstake when *every* set field matches the stake's event metadata:\n\n- **sportId** (string, optional) - Restrict to a specific sport (UUID, operator-defined\n  — e.g. football, basketball, tennis). `null` = any sport.\n\n- **categoryId** (string, optional) - Restrict to a category — typically a country /\n  region inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n  `null` = any category.\n\n- **tournamentId** (string, optional) - Restrict to a tournament inside a category\n  (UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). `null` = any\n  tournament.\n\n- **eventId** (string, optional) - Restrict to a single event / match (UUID,\n  operator-defined). `null` = any event.\n\n- **markets** (array of `MarketType`, required) - Allow-listed market identifiers\n  from the generated `MarketType` enum (lowercase enum names from the SportsbookSchema).\n  Examples: `score_1x2`, `score_ou`, `score_dc`, `score_both_to_score_yes_no`,\n  `score_ht_ft`, `score_winning_margin`, `score_exact_number`, `corner_1x2`,\n  `yellow_card_1x2`. **Empty array means any market.**\n\n- **betRule** (object, optional) - Bet-shape restrictions. **All `betRule` fields\n  are nullable; `null` (or empty for set-typed fields) means \"no restriction on this\n  dimension\".** A stake is accepted when every set field matches.\n\n  - **betTypes** (array of `BetHashType`, required) - Allowed bet types from the\n    `BetHashType` enum. The JSON wire form is **lowercase** (set by Jackson\n    `@JsonProperty` on the enum). Possible values:\n\n    - `single` - A single selection bet.\n    - `parlay` - Accumulator bet (multiple selections combined; all must win).\n      The `accumulator*` betRule fields below apply only to this bet type.\n    - `system` - System bet (combinations of accumulators).\n\n    **Empty array means any bet type.**\n\n  - **live** (boolean, optional) - `true` = live betting only, `false` = pre-match\n    only, `null` = both allowed.\n  - **singleMinOdd** (number, optional) - Minimum odd for `single` bets. Ignored\n    for non-single bet types. Applied to the bet's single odd at placement time.\n  - **accumulatorTotalOdds** (number, optional) - Minimum total odds for a `parlay`\n    (the product of all selection odds). Ignored for non-`parlay` bet types.\n  - **accumulatorAtLeastOdd** (number, optional) - At least one selection in the\n    `parlay` must have an odd ≥ this value. Combined with\n    `accumulatorMinOddPerSelection` for fine-grained control.\n  - **accumulatorMinNumberOfSelections** (integer, optional) - Minimum number of\n    legs (selections) in the `parlay`.\n  - **accumulatorMaxNumberOfSelections** (integer, optional) - Maximum number of\n    legs in the `parlay`.\n  - **accumulatorMinOddPerSelection** (number, optional) - Minimum odd that\n    **every** selection in the `parlay` must meet.\n\n### `freeBetUseType` — FreeBetUseType union\n\nDiscriminated by `__payloadKind`. Two concrete kinds:\n\n- **`FreeBetAllBalanceUseType`** - The stake must consist 100% of free-bet money. Real\n  money cannot be mixed in.\n\n  - **isMustBeStakedAtOnce** (boolean, required) - When `true`, the entire free-bet\n    balance must be wagered in a **single** bet (the player cannot split the\n    balance across multiple bets). When `false`, the player may place multiple bets\n    until the balance is exhausted, subject to `maxAmountOfBets`.\n\n- **`FreeBetPartialBalanceUseType`** - The stake may mix free-bet money with real\n  money. Each bet's free-bet portion is bounded.\n\n  - **minValue** (MoneyBag, optional) - Minimum free-bet amount per bet. `null` =\n    no minimum.\n  - **maxValue** (MoneyBag, optional) - Maximum free-bet amount per bet. `null` =\n    no maximum.\n\n### `MoneyBag`\n\nShape — examples in this document use only the `system` amount in a single currency:\n\n```json\n{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n```\n\n- **system** (`{amount, currency}`, required) - The amount in the bonus's currency.\n  The `amount` is a **string** (decimal with no implied scaling — the bonus engine\n  stores monetary values in raw integer minor-unit form, e.g. `\"50000\"` = 500.00 TRY).\n- **additional** (array, required) - Per-currency overrides for cross-currency\n  bonuses. When the player's currency matches an entry's `currency`, the entry's\n  `amount` is used directly; otherwise the `system` amount is converted via the\n  operator's currency-pair rates. Single-currency bonuses (the common case) emit\n  an empty array, as in all examples in this document.\n\n## Request Examples\n\n### Mode 1 — Catalogue lookup\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true\n}\n```\n\n### Mode 2 — Available bonuses for a specific player\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n```\n\n### Mode 3 — Registration bonuses only\n\n```json\n{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)\n\nThe faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n**Demonstrates the unrestricted shape:** `filters[0]` has every dimension `null` /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). `freeBetUseType` is `FreeBetAllBalanceUseType` with\n`isMustBeStakedAtOnce: true`, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Internal Free Bet (populated sportsbook)\n\nA 100 TRY free bet for **Premier League pre-match singles and parlays**.\n**Demonstrates every populated dimension using real SportsbookSchema values:**\n\n- Sport / category / tournament gating: `sportId` (Football),\n  `categoryId` (England), `tournamentId` (Premier League).\n- Three real `MarketType` values allow-listed:\n  `[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]`.\n- `betTypes: [\"single\", \"parlay\"]` — uses real `BetHashType` JSON values\n  (lowercase via Jackson `@JsonProperty`).\n- `live: false` — pre-match only.\n- `single` bets must have an odd ≥ `1.5`.\n- `parlay` bets must have total odds ≥ `3.0`, between `3` and `10` selections, every\n  selection at min odd `1.2`, with at least one selection at min odd `1.3`.\n- Stake band `25 TRY ≤ stake ≤ 100 TRY`, max win `1000 TRY`, max `5` bets.\n- 72-hour validity once activated.\n- `freeBetUseType` is `FreeBetPartialBalanceUseType` with the same `25-100 TRY` bounds\n  per bet — meaning the player may combine free-bet money with real money on the\n  same stake.\n- `isAutoActivates: false` — the partner must call `activate-player-bonus` after\n  claim.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty result\n\n```json\n{\n    \"bonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- Both `available` and `tag` omitted.\n- `tag` provided but not equal to `\"REGISTRATION\"` (case-insensitive).\n- Malformed `brandId` (non-integer) or missing `Authorization`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\nOccurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nOccurs in Mode 2 when the `externalUserId` cannot be resolved or registered\nautomatically.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\nOccurs when `Authorization` is missing, malformed, or does not match a known brand\ncredential.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 403 Forbidden - IP not whitelisted\n\nOccurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.\n\n**Example Error Response (HTML body, status 403):**\n\n```text\nIP <client-ip> is not presented in white list\n```\n\n### 500 Internal Server Error - Unknown Error\n\nOccurs when an unexpected server error happens.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Sportsbook free-bet only.** This integration is purpose-built for\n   `INTERNAL_FREE_BET` bonuses on the sportsbook product\n   (`InternalFreeBetSportsbookCriteria` payload). `winSize` is always `null`,\n   `wagering` is always `null`. All limits and rules are encoded inside\n   `bonusSize.rule.productRules[].criteria` and `bonusSize.rule.freeBetUseType`. Other\n   `bonusType` values and non-sportsbook free-bet criteria may appear in the catalogue\n   and should be filtered out client-side.\n\n2. **Real schema values.** `betRule.betTypes` uses the **`BetHashType`** enum with\n   lowercase JSON values (`\"single\"`, `\"parlay\"`, `\"system\"`) — the `parlay` value is\n   the schema name for accumulator bets. `markets` uses the **`MarketType`** enum\n   from the generated SportsbookSchema (lowercase names like `score_1x2`, `score_ou`,\n   `score_both_to_score_yes_no`).\n\n3. **Visibility flag handling.** In Mode 1 (catalogue) the operator-side\n   `\"Show For Players\"` visibility flag is ignored — partners see the full enabled\n   catalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n   `isShownForPlayers: false` are hidden.\n\n4. **Mode 2 player registration side-effect.** When `externalUserId` is unknown to\n   Sumstats, the system attempts to register the player automatically before\n   evaluating eligibility. Subsequent calls for the same `externalUserId` skip\n   this step. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n5. **Polymorphic `__payloadKind` discriminator.** All polymorphic objects\n   (`bonusSize`, `criteria`, `freeBetUseType`, `bonusSize.amount`) carry a\n   `__payloadKind` field containing the concrete payload kind. Partners must\n   discriminate on this field — adding new payload kinds in the future is the\n   standard evolution path.\n\n6. **`MoneyBag.system` semantics.** `system` carries the canonical amount in the\n   operator's accounting currency. When the player's currency matches an entry in\n   `additional`, that override is used directly; otherwise the system entry is\n   converted via the operator's currency-pair rates. Partners should prefer the\n   `additional` entry matching the player's currency for display.\n\n7. **Currencies and bonus selection.** The `currencies` array on the bonus is the\n   set of currencies the bonus supports. In Mode 2, only bonuses whose `currencies`\n   array contains the player's currency are returned.\n\n8. **Empty filter list semantics.** `criteria.filters` is an array — an **empty\n   array** means \"no narrowing\": the free bet may be staked on any sportsbook event.\n   **A non-empty filter list is OR'd:** a stake is allowed when at least one filter\n   accepts it.\n\n9. **Empty-vs-null in `betRule`.** `betRule.betTypes: []` and `betRule.markets: []`\n   mean \"any\" (no restriction); `betRule.live: null` means \"any live mode\"; numeric /\n   integer fields use `null` for \"no restriction\". The semantics differ — empty array\n   on `betTypes` / `markets`, `null` on the rest.\n\n10. **`isAutoActivates` impact on the claim flow.** When `isAutoActivates: true`,\n    calling `claim-bonus-for-player` immediately moves the player bonus to\n    `IN_PROGRESS`. When `false`, the partner must call `activate-player-bonus` within\n    `timeForActivationInHours` hours.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}"},{"id":"13b2b86c-3db0-4a4a-ae64-97ffdaff9d4e","name":"success — Empty","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"# Endpoint for Finding Available Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-available-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet bonuses** currently offered\nby the operator. Three usage modes are selected via the request body fields:\n\n- **Mode 1 — All available bonuses (catalogue).** `available: true`, `externalUserId`\n  omitted. Returns all enabled, in-activity-window bonuses. The operator-side\n  `\"Show For Players\"` visibility flag is **ignored** in this mode — the full catalogue\n  is exposed so the partner can plan campaigns.\n- **Mode 2 — Available bonuses for a specific player.** `available: true`,\n  `externalUserId` set. Returns only the bonuses available *for that player*: per-player\n  limits, claim eligibility rules and the operator-side visibility flag are honoured,\n  and bonuses already claimed/active for the player are excluded. If the external\n  player is unknown to Sumstats, the system attempts to register them automatically\n  before evaluating eligibility.\n- **Mode 3 — Registration bonuses only.** `tag: \"REGISTRATION\"` (with or without\n  `available`). Returns the subset of bonuses tagged for new-player registration flows.\n\nThe response is **not paginated** — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(`bonusSize.__payloadKind = \"FreeBetSize\"`) describing the substantive offer; the\npartner is expected to discriminate on `__payloadKind` for nested polymorphic objects\n(`criteria`, `freeBetUseType`, `bonusSize.amount`).\n\n> **Scope.** This integration is purpose-built for `INTERNAL_FREE_BET` bonuses on the\n> sportsbook product (`InternalFreeBetSportsbookCriteria` payload). Other bonus types\n> (`CUSTOM`, `FIRST_DEPOSIT`, `EXTERNAL_FREE_BET`, `EXTERNAL_FREE_SPINS_WITH_WAGERING`,\n> `INTERNAL_FREE_SPINS_WITH_WAGERING`, `CASHBACK`) and non-sportsbook free-bet\n> criteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n> `bonusType: \"INTERNAL_FREE_BET\"` with\n> `bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"`\n> client-side.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the brand\n  encoded in the HTTP Basic credentials. Used together with `Authorization` for\n  credential lookup.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only — partners on the new contract must send `brandId`.\n\n- **available** (boolean, optional) - When `true` activates Mode 1 or Mode 2 selection.\n  When omitted, `tag` must be set, otherwise the request is rejected with\n  `BAD_REQUEST`.\n\n- **externalUserId** (string, optional) - External player id in the operator system.\n  When set, switches the call to Mode 2 (per-player filtering). If the player is\n  unknown to Sumstats, the system attempts to register them automatically.\n\n- **tag** (string, optional) - When set, must be `\"REGISTRATION\"` (case-insensitive)\n  and switches the call to Mode 3. Any other value is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **bonuses** (array of objects, required) - List of bonus objects matching the query.\n  Empty list when nothing matches. The partner-facing slim shape drops\n  internal/operational fields (`descriptionTitle`, `descriptionBonusRules`,\n  `fullTermsAndConditions`, `descriptionFiles`, `isShownForPlayers`, `bonusTags`,\n  `shareLimitsId`, `eligibilityClaimRulesCompletionInfo`, `notSatisfiedMatchResults`,\n  `satisfiedMatchResults`, `operatorId`, `ruleIds`, `removedAt`, `updatedAt`,\n  `playerGroupIds`, `bonusOverridableFeatures`).\n\n  Each bonus object has the structure documented under **Bonus Fields** below.\n\n### Bonus Fields\n\nThe slim partner-facing bonus shape. Field-by-field semantics:\n\n- **id** (string, required) - Bonus identifier in **UUID v7** format. This is the\n  *catalogue* id of the bonus configuration, not a per-player id. Pass to\n  `claim-bonus-for-player`, `activate-player-bonus`, `cancel-player-bonus`. Stable\n  across partner calls — repeated `find-available-bonuses` requests return the same\n  `id` for the same operator-configured bonus until the operator deletes the\n  configuration.\n\n- **name** (array of `{locale, translate}`, required) - Localised bonus names. Each\n  entry binds a `locale` (BCP-47 / ICU locale code, e.g. `en_US`, `de_DE`) to\n  the human-readable bonus name in that locale. Partners should pick the entry\n  matching the player's locale; when no exact match exists, fall back to `en_US` or\n  the first entry. Bonuses are guaranteed to have **at least one** translation\n  (typically `en_US`).\n\n- **bonusType** (enum, required) - High-level bonus kind. **For this integration's\n  contract, the relevant value is `INTERNAL_FREE_BET`.** Drives which payload shapes\n  appear inside `bonusSize`. Other types may appear in the catalogue but are out of\n  scope — partners should filter the response to `bonusType: \"INTERNAL_FREE_BET\"`\n  client-side.\n\n- **status** (enum, required) - Lifecycle status of the bonus on the operator side.\n  Possible values:\n\n  - `NOT_STARTED` - Created and saved but the activity window has not started yet.\n  - `SCHEDULED` - Inside the configured activity window but the bonus is scheduled to go active at a later point.\n  - `ACTIVE` - Enabled and inside the activity window. Only `ACTIVE` bonuses can be claimed.\n  - `DISABLED` - Operator switched the bonus off from the admin panel.\n  - `EXPIRED` - Activity window has passed.\n  - `REMOVED` - Operator deleted the bonus configuration. Catalogue audits only — not claimable.\n\n  Only `ACTIVE` bonuses can be claimed — `find-available-bonuses` does not return\n  non-`ACTIVE` bonuses by default; the field is informational for catalogue audits.\n\n- **enabled** (boolean, required) - `false` when the operator has explicitly disabled\n  the bonus from the admin panel. A bonus with `status: ACTIVE` and `enabled: false`\n  is unavailable for new claims and will not appear in Mode 2 (per-player) responses.\n  Mode 1 (catalogue) responses include disabled bonuses for partner audit purposes.\n\n- **promotionCode** (string, optional) - Operator-issued promotion code (e.g.\n  `\"500TRYFREEBET\"`, `\"EPL100\"`). When set, the bonus is gated by the code on the\n  player-facing surface — players can only claim it through a promo-code flow.\n  `null` when the bonus is freely claimable. **Partners using this integration claim\n  by `bonusId` directly and bypass the promo-code gate**, but the field is exposed\n  so partners can mirror operator-side promo flows on their UI.\n\n- **activityTime** (object, optional) - Activity window. `null` means always on\n  (no time gate). The shape mirrors the internal `ActivityTime` record — at most\n  one of `timePeriod` / `timeSchedule` is populated:\n\n  - **timePeriod** (object, optional) - Continuous activity window.\n    - **timeRange** (object, required) - Half-open period.\n      - **from** (long, optional) - Start of the window in **epoch millis (UTC)**.\n        `null` means open-ended start.\n      - **to** (long, optional) - End of the window in **epoch millis (UTC)**.\n        `null` means open-ended end.\n    - **isShownBeforePeriod** (boolean, required) - Whether the bonus is exposed\n      to players before `timeRange.from`.\n    - **isShownAfterPeriod** (boolean, required) - Whether the bonus is exposed\n      after `timeRange.to`.\n    - **shownBeforePeriodMinutes** (long, optional) - How long before\n      `timeRange.from` the bonus becomes visible.\n    - **shownAfterPeriodMinutes** (long, optional) - How long after\n      `timeRange.to` the bonus remains visible.\n  - **timeSchedule** (object, optional) - Recurring activity schedule.\n    Polymorphic on `__payloadKind`:\n    - `HoursOfDayTimeSchedule` — recurring hours-of-day periods (`periods`).\n    - `DaysOfWeekTimeSchedule` — recurring per-day-of-week periods\n      (`periodsByDay`).\n    - `DaysOfMonthTimeSchedule` — recurring per-day-of-month periods\n      (`periodsByDay`).\n\n    `null` when activity is window-only.\n\n  Outside the window the bonus is unclaimable (Sumstats responds with\n  `BONUS_NOT_AVAILABLE` (303) on claim).\n\n- **timeForActivationInHours** (integer, optional) - Hours after claim during which\n  the player must activate the bonus (i.e. how long the `CLAIMED → IN_PROGRESS`\n  transition is allowed). `null` = unlimited (the player bonus stays in `CLAIMED`\n  until activation or manual cancel). Used by Sumstats to compute `expiredOnClaimAt`\n  on the resulting player bonus. Example: `168` means the player has seven days to\n  activate.\n\n- **currencies** (array of strings, required) - Currencies the bonus supports\n  (ISO 4217 codes — `TRY`, `EUR`, `USD`, …). The bonus can only be claimed by players\n  whose account currency is in this set. In Mode 2, only bonuses whose `currencies`\n  array contains the player's currency are returned. Empty array indicates a\n  misconfiguration on the operator side.\n\n- **isAutoActivates** (boolean, required) - When `true`, the bonus auto-activates on\n  claim — partners do **not** need to call `activate-player-bonus`. The\n  `claim-bonus-for-player` response carries `status: \"IN_PROGRESS\"` and a populated\n  `activatedAt`. When `false`, the partner must explicitly call `activate-player-bonus`\n  within `timeForActivationInHours` hours, or the player bonus expires.\n\n- **bonusSize** (object, required) - Substantive offer payload describing the\n  free-bet rule and amount. **For `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind`\n  is always `\"FreeBetSize\"`.** See **FreeBetSize** below.\n\n- **winSize** (object, optional) - Cap on potential winnings. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — the substantive limits are encoded inside the\n  free-bet criteria (`bonusSize.rule.productRules[].criteria.maxWinAllowed`).\n\n- **wagering** (object, optional) - Wagering rules. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — free bets do not have a turnover requirement; the\n  free bet either wins, loses, or expires per the criteria rules.\n\n### `bonusSize` — FreeBetSize\n\nFor `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind = \"FreeBetSize\"`. The\n`FreeBetSize` payload has two top-level fields:\n\n- **rule** (object, required) - The free-bet rule — defines per-product criteria,\n  free-bet use type, and validity. See **FreeBetRule** below.\n- **amount** (object, optional) - Total monetary value handed to the player as a\n  free-bet balance when the bonus is activated. Polymorphic on `__payloadKind`. Two\n  practical kinds for free bets:\n\n  - **MonetarySize** - Fixed amount.\n\n    - **money** (MoneyBag, required) - The free-bet balance. See **MoneyBag** below.\n\n  - **PercentageSize** - Percentage of a baseline (rare for free bets).\n\n    - **percentage** (number, required) - Percentage value, e.g. `100.0` = 100%.\n    - **maxAmount** (MoneyBag, optional) - Upper cap on the resulting balance.\n    - **minAmount** (MoneyBag, optional) - Lower floor on the resulting balance.\n\n### `bonusSize.rule` — FreeBetRule\n\n**Object:**\n\n- **productRules** (array of `FreeBetProductRule`, required, length ≥ 1) - Per-product\n  free-bet criteria. **For sportsbook free bets there is a single entry with\n  `product: \"SPORTS\"`.**\n\n  Each `FreeBetProductRule` has:\n\n  - **note** (array of `{locale, translate}`, optional) - Operator-supplied note\n    describing the rule, localised. `null` when no note was set.\n  - **title** (array of `{locale, translate}`, optional) - Operator-supplied title\n    for the rule, localised. `null` when no title was set.\n  - **product** (string, required) - For this integration's scope, always `\"SPORTS\"`.\n  - **criteria** (object, required) - Per-product limit rules. Polymorphic on\n    `__payloadKind`. **For sportsbook free bets,\n    `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.** See\n    **InternalFreeBetSportsbookCriteria** below.\n\n- **validityInHours** (integer, required) - Lifetime of the *activated* bonus, in\n  hours. `0` = unlimited (the bonus runs until the free-bet balance is exhausted,\n  the bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\n  Used by Sumstats to compute `expiredAt` on the activated player bonus.\n\n- **note** (array of `{locale, translate}`, optional) - Free-form operator note for\n  the rule as a whole, localised. `null` when no note was set.\n\n- **freeBetUseType** (object, required) - How the free-bet money composes the\n  player's stake. Polymorphic on `__payloadKind`. See **FreeBetUseType union** below.\n\n### `criteria` — InternalFreeBetSportsbookCriteria\n\nFor sportsbook free bets, `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.\nTop-level fields:\n\n- **filters** (array of `InternalFreeBetSportsbookFilter`, required) - Filter list\n  narrowing where the free bet may be staked. **An empty filter list means \"no\n  narrowing\"** (the free bet may be staked on any sportsbook event). Multiple filters\n  are OR'd: a stake is allowed if **at least one** filter accepts it. See\n  **InternalFreeBetSportsbookFilter** below.\n\n- **minValue** (MoneyBag, optional) - Minimum bet stake required. `null` = no\n  minimum. Stakes below this are rejected by the bet placement engine.\n\n- **maxValue** (MoneyBag, optional) - Maximum bet stake allowed. `null` = no\n  maximum. Stakes above this are rejected.\n\n- **maxWinAllowed** (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\n  single free-bet stake are capped at this amount. `null` = no cap (free bet pays\n  out the full computed winnings).\n\n- **maxAmountOfBets** (integer, optional) - Maximum number of bets the player may\n  place using the free-bet balance. `null` = unlimited (the bonus runs until the\n  free-bet balance is exhausted or expires). Once the limit is hit, the bonus\n  transitions to `COMPLETED` automatically.\n\n#### `filters[]` — InternalFreeBetSportsbookFilter\n\nNarrows the events on which the free bet may be staked. **All scalar fields are\nnullable; `null` means \"no restriction on this dimension\".** The filter accepts a\nstake when *every* set field matches the stake's event metadata:\n\n- **sportId** (string, optional) - Restrict to a specific sport (UUID, operator-defined\n  — e.g. football, basketball, tennis). `null` = any sport.\n\n- **categoryId** (string, optional) - Restrict to a category — typically a country /\n  region inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n  `null` = any category.\n\n- **tournamentId** (string, optional) - Restrict to a tournament inside a category\n  (UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). `null` = any\n  tournament.\n\n- **eventId** (string, optional) - Restrict to a single event / match (UUID,\n  operator-defined). `null` = any event.\n\n- **markets** (array of `MarketType`, required) - Allow-listed market identifiers\n  from the generated `MarketType` enum (lowercase enum names from the SportsbookSchema).\n  Examples: `score_1x2`, `score_ou`, `score_dc`, `score_both_to_score_yes_no`,\n  `score_ht_ft`, `score_winning_margin`, `score_exact_number`, `corner_1x2`,\n  `yellow_card_1x2`. **Empty array means any market.**\n\n- **betRule** (object, optional) - Bet-shape restrictions. **All `betRule` fields\n  are nullable; `null` (or empty for set-typed fields) means \"no restriction on this\n  dimension\".** A stake is accepted when every set field matches.\n\n  - **betTypes** (array of `BetHashType`, required) - Allowed bet types from the\n    `BetHashType` enum. The JSON wire form is **lowercase** (set by Jackson\n    `@JsonProperty` on the enum). Possible values:\n\n    - `single` - A single selection bet.\n    - `parlay` - Accumulator bet (multiple selections combined; all must win).\n      The `accumulator*` betRule fields below apply only to this bet type.\n    - `system` - System bet (combinations of accumulators).\n\n    **Empty array means any bet type.**\n\n  - **live** (boolean, optional) - `true` = live betting only, `false` = pre-match\n    only, `null` = both allowed.\n  - **singleMinOdd** (number, optional) - Minimum odd for `single` bets. Ignored\n    for non-single bet types. Applied to the bet's single odd at placement time.\n  - **accumulatorTotalOdds** (number, optional) - Minimum total odds for a `parlay`\n    (the product of all selection odds). Ignored for non-`parlay` bet types.\n  - **accumulatorAtLeastOdd** (number, optional) - At least one selection in the\n    `parlay` must have an odd ≥ this value. Combined with\n    `accumulatorMinOddPerSelection` for fine-grained control.\n  - **accumulatorMinNumberOfSelections** (integer, optional) - Minimum number of\n    legs (selections) in the `parlay`.\n  - **accumulatorMaxNumberOfSelections** (integer, optional) - Maximum number of\n    legs in the `parlay`.\n  - **accumulatorMinOddPerSelection** (number, optional) - Minimum odd that\n    **every** selection in the `parlay` must meet.\n\n### `freeBetUseType` — FreeBetUseType union\n\nDiscriminated by `__payloadKind`. Two concrete kinds:\n\n- **`FreeBetAllBalanceUseType`** - The stake must consist 100% of free-bet money. Real\n  money cannot be mixed in.\n\n  - **isMustBeStakedAtOnce** (boolean, required) - When `true`, the entire free-bet\n    balance must be wagered in a **single** bet (the player cannot split the\n    balance across multiple bets). When `false`, the player may place multiple bets\n    until the balance is exhausted, subject to `maxAmountOfBets`.\n\n- **`FreeBetPartialBalanceUseType`** - The stake may mix free-bet money with real\n  money. Each bet's free-bet portion is bounded.\n\n  - **minValue** (MoneyBag, optional) - Minimum free-bet amount per bet. `null` =\n    no minimum.\n  - **maxValue** (MoneyBag, optional) - Maximum free-bet amount per bet. `null` =\n    no maximum.\n\n### `MoneyBag`\n\nShape — examples in this document use only the `system` amount in a single currency:\n\n```json\n{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n```\n\n- **system** (`{amount, currency}`, required) - The amount in the bonus's currency.\n  The `amount` is a **string** (decimal with no implied scaling — the bonus engine\n  stores monetary values in raw integer minor-unit form, e.g. `\"50000\"` = 500.00 TRY).\n- **additional** (array, required) - Per-currency overrides for cross-currency\n  bonuses. When the player's currency matches an entry's `currency`, the entry's\n  `amount` is used directly; otherwise the `system` amount is converted via the\n  operator's currency-pair rates. Single-currency bonuses (the common case) emit\n  an empty array, as in all examples in this document.\n\n## Request Examples\n\n### Mode 1 — Catalogue lookup\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true\n}\n```\n\n### Mode 2 — Available bonuses for a specific player\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n```\n\n### Mode 3 — Registration bonuses only\n\n```json\n{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)\n\nThe faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n**Demonstrates the unrestricted shape:** `filters[0]` has every dimension `null` /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). `freeBetUseType` is `FreeBetAllBalanceUseType` with\n`isMustBeStakedAtOnce: true`, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Internal Free Bet (populated sportsbook)\n\nA 100 TRY free bet for **Premier League pre-match singles and parlays**.\n**Demonstrates every populated dimension using real SportsbookSchema values:**\n\n- Sport / category / tournament gating: `sportId` (Football),\n  `categoryId` (England), `tournamentId` (Premier League).\n- Three real `MarketType` values allow-listed:\n  `[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]`.\n- `betTypes: [\"single\", \"parlay\"]` — uses real `BetHashType` JSON values\n  (lowercase via Jackson `@JsonProperty`).\n- `live: false` — pre-match only.\n- `single` bets must have an odd ≥ `1.5`.\n- `parlay` bets must have total odds ≥ `3.0`, between `3` and `10` selections, every\n  selection at min odd `1.2`, with at least one selection at min odd `1.3`.\n- Stake band `25 TRY ≤ stake ≤ 100 TRY`, max win `1000 TRY`, max `5` bets.\n- 72-hour validity once activated.\n- `freeBetUseType` is `FreeBetPartialBalanceUseType` with the same `25-100 TRY` bounds\n  per bet — meaning the player may combine free-bet money with real money on the\n  same stake.\n- `isAutoActivates: false` — the partner must call `activate-player-bonus` after\n  claim.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty result\n\n```json\n{\n    \"bonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- Both `available` and `tag` omitted.\n- `tag` provided but not equal to `\"REGISTRATION\"` (case-insensitive).\n- Malformed `brandId` (non-integer) or missing `Authorization`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\nOccurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nOccurs in Mode 2 when the `externalUserId` cannot be resolved or registered\nautomatically.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\nOccurs when `Authorization` is missing, malformed, or does not match a known brand\ncredential.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 403 Forbidden - IP not whitelisted\n\nOccurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.\n\n**Example Error Response (HTML body, status 403):**\n\n```text\nIP <client-ip> is not presented in white list\n```\n\n### 500 Internal Server Error - Unknown Error\n\nOccurs when an unexpected server error happens.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Sportsbook free-bet only.** This integration is purpose-built for\n   `INTERNAL_FREE_BET` bonuses on the sportsbook product\n   (`InternalFreeBetSportsbookCriteria` payload). `winSize` is always `null`,\n   `wagering` is always `null`. All limits and rules are encoded inside\n   `bonusSize.rule.productRules[].criteria` and `bonusSize.rule.freeBetUseType`. Other\n   `bonusType` values and non-sportsbook free-bet criteria may appear in the catalogue\n   and should be filtered out client-side.\n\n2. **Real schema values.** `betRule.betTypes` uses the **`BetHashType`** enum with\n   lowercase JSON values (`\"single\"`, `\"parlay\"`, `\"system\"`) — the `parlay` value is\n   the schema name for accumulator bets. `markets` uses the **`MarketType`** enum\n   from the generated SportsbookSchema (lowercase names like `score_1x2`, `score_ou`,\n   `score_both_to_score_yes_no`).\n\n3. **Visibility flag handling.** In Mode 1 (catalogue) the operator-side\n   `\"Show For Players\"` visibility flag is ignored — partners see the full enabled\n   catalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n   `isShownForPlayers: false` are hidden.\n\n4. **Mode 2 player registration side-effect.** When `externalUserId` is unknown to\n   Sumstats, the system attempts to register the player automatically before\n   evaluating eligibility. Subsequent calls for the same `externalUserId` skip\n   this step. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n5. **Polymorphic `__payloadKind` discriminator.** All polymorphic objects\n   (`bonusSize`, `criteria`, `freeBetUseType`, `bonusSize.amount`) carry a\n   `__payloadKind` field containing the concrete payload kind. Partners must\n   discriminate on this field — adding new payload kinds in the future is the\n   standard evolution path.\n\n6. **`MoneyBag.system` semantics.** `system` carries the canonical amount in the\n   operator's accounting currency. When the player's currency matches an entry in\n   `additional`, that override is used directly; otherwise the system entry is\n   converted via the operator's currency-pair rates. Partners should prefer the\n   `additional` entry matching the player's currency for display.\n\n7. **Currencies and bonus selection.** The `currencies` array on the bonus is the\n   set of currencies the bonus supports. In Mode 2, only bonuses whose `currencies`\n   array contains the player's currency are returned.\n\n8. **Empty filter list semantics.** `criteria.filters` is an array — an **empty\n   array** means \"no narrowing\": the free bet may be staked on any sportsbook event.\n   **A non-empty filter list is OR'd:** a stake is allowed when at least one filter\n   accepts it.\n\n9. **Empty-vs-null in `betRule`.** `betRule.betTypes: []` and `betRule.markets: []`\n   mean \"any\" (no restriction); `betRule.live: null` means \"any live mode\"; numeric /\n   integer fields use `null` for \"no restriction\". The semantics differ — empty array\n   on `betTypes` / `markets`, `null` on the rest.\n\n10. **`isAutoActivates` impact on the claim flow.** When `isAutoActivates: true`,\n    calling `claim-bonus-for-player` immediately moves the player bonus to\n    `IN_PROGRESS`. When `false`, the partner must call `activate-player-bonus` within\n    `timeForActivationInHours` hours.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"bonuses\": []\n}"},{"id":"3a19312f-6408-4099-9ff9-151a115acf34","name":"fail — bad request","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"# Endpoint for Finding Available Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-available-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet bonuses** currently offered\nby the operator. Three usage modes are selected via the request body fields:\n\n- **Mode 1 — All available bonuses (catalogue).** `available: true`, `externalUserId`\n  omitted. Returns all enabled, in-activity-window bonuses. The operator-side\n  `\"Show For Players\"` visibility flag is **ignored** in this mode — the full catalogue\n  is exposed so the partner can plan campaigns.\n- **Mode 2 — Available bonuses for a specific player.** `available: true`,\n  `externalUserId` set. Returns only the bonuses available *for that player*: per-player\n  limits, claim eligibility rules and the operator-side visibility flag are honoured,\n  and bonuses already claimed/active for the player are excluded. If the external\n  player is unknown to Sumstats, the system attempts to register them automatically\n  before evaluating eligibility.\n- **Mode 3 — Registration bonuses only.** `tag: \"REGISTRATION\"` (with or without\n  `available`). Returns the subset of bonuses tagged for new-player registration flows.\n\nThe response is **not paginated** — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(`bonusSize.__payloadKind = \"FreeBetSize\"`) describing the substantive offer; the\npartner is expected to discriminate on `__payloadKind` for nested polymorphic objects\n(`criteria`, `freeBetUseType`, `bonusSize.amount`).\n\n> **Scope.** This integration is purpose-built for `INTERNAL_FREE_BET` bonuses on the\n> sportsbook product (`InternalFreeBetSportsbookCriteria` payload). Other bonus types\n> (`CUSTOM`, `FIRST_DEPOSIT`, `EXTERNAL_FREE_BET`, `EXTERNAL_FREE_SPINS_WITH_WAGERING`,\n> `INTERNAL_FREE_SPINS_WITH_WAGERING`, `CASHBACK`) and non-sportsbook free-bet\n> criteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n> `bonusType: \"INTERNAL_FREE_BET\"` with\n> `bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"`\n> client-side.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the brand\n  encoded in the HTTP Basic credentials. Used together with `Authorization` for\n  credential lookup.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only — partners on the new contract must send `brandId`.\n\n- **available** (boolean, optional) - When `true` activates Mode 1 or Mode 2 selection.\n  When omitted, `tag` must be set, otherwise the request is rejected with\n  `BAD_REQUEST`.\n\n- **externalUserId** (string, optional) - External player id in the operator system.\n  When set, switches the call to Mode 2 (per-player filtering). If the player is\n  unknown to Sumstats, the system attempts to register them automatically.\n\n- **tag** (string, optional) - When set, must be `\"REGISTRATION\"` (case-insensitive)\n  and switches the call to Mode 3. Any other value is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **bonuses** (array of objects, required) - List of bonus objects matching the query.\n  Empty list when nothing matches. The partner-facing slim shape drops\n  internal/operational fields (`descriptionTitle`, `descriptionBonusRules`,\n  `fullTermsAndConditions`, `descriptionFiles`, `isShownForPlayers`, `bonusTags`,\n  `shareLimitsId`, `eligibilityClaimRulesCompletionInfo`, `notSatisfiedMatchResults`,\n  `satisfiedMatchResults`, `operatorId`, `ruleIds`, `removedAt`, `updatedAt`,\n  `playerGroupIds`, `bonusOverridableFeatures`).\n\n  Each bonus object has the structure documented under **Bonus Fields** below.\n\n### Bonus Fields\n\nThe slim partner-facing bonus shape. Field-by-field semantics:\n\n- **id** (string, required) - Bonus identifier in **UUID v7** format. This is the\n  *catalogue* id of the bonus configuration, not a per-player id. Pass to\n  `claim-bonus-for-player`, `activate-player-bonus`, `cancel-player-bonus`. Stable\n  across partner calls — repeated `find-available-bonuses` requests return the same\n  `id` for the same operator-configured bonus until the operator deletes the\n  configuration.\n\n- **name** (array of `{locale, translate}`, required) - Localised bonus names. Each\n  entry binds a `locale` (BCP-47 / ICU locale code, e.g. `en_US`, `de_DE`) to\n  the human-readable bonus name in that locale. Partners should pick the entry\n  matching the player's locale; when no exact match exists, fall back to `en_US` or\n  the first entry. Bonuses are guaranteed to have **at least one** translation\n  (typically `en_US`).\n\n- **bonusType** (enum, required) - High-level bonus kind. **For this integration's\n  contract, the relevant value is `INTERNAL_FREE_BET`.** Drives which payload shapes\n  appear inside `bonusSize`. Other types may appear in the catalogue but are out of\n  scope — partners should filter the response to `bonusType: \"INTERNAL_FREE_BET\"`\n  client-side.\n\n- **status** (enum, required) - Lifecycle status of the bonus on the operator side.\n  Possible values:\n\n  - `NOT_STARTED` - Created and saved but the activity window has not started yet.\n  - `SCHEDULED` - Inside the configured activity window but the bonus is scheduled to go active at a later point.\n  - `ACTIVE` - Enabled and inside the activity window. Only `ACTIVE` bonuses can be claimed.\n  - `DISABLED` - Operator switched the bonus off from the admin panel.\n  - `EXPIRED` - Activity window has passed.\n  - `REMOVED` - Operator deleted the bonus configuration. Catalogue audits only — not claimable.\n\n  Only `ACTIVE` bonuses can be claimed — `find-available-bonuses` does not return\n  non-`ACTIVE` bonuses by default; the field is informational for catalogue audits.\n\n- **enabled** (boolean, required) - `false` when the operator has explicitly disabled\n  the bonus from the admin panel. A bonus with `status: ACTIVE` and `enabled: false`\n  is unavailable for new claims and will not appear in Mode 2 (per-player) responses.\n  Mode 1 (catalogue) responses include disabled bonuses for partner audit purposes.\n\n- **promotionCode** (string, optional) - Operator-issued promotion code (e.g.\n  `\"500TRYFREEBET\"`, `\"EPL100\"`). When set, the bonus is gated by the code on the\n  player-facing surface — players can only claim it through a promo-code flow.\n  `null` when the bonus is freely claimable. **Partners using this integration claim\n  by `bonusId` directly and bypass the promo-code gate**, but the field is exposed\n  so partners can mirror operator-side promo flows on their UI.\n\n- **activityTime** (object, optional) - Activity window. `null` means always on\n  (no time gate). The shape mirrors the internal `ActivityTime` record — at most\n  one of `timePeriod` / `timeSchedule` is populated:\n\n  - **timePeriod** (object, optional) - Continuous activity window.\n    - **timeRange** (object, required) - Half-open period.\n      - **from** (long, optional) - Start of the window in **epoch millis (UTC)**.\n        `null` means open-ended start.\n      - **to** (long, optional) - End of the window in **epoch millis (UTC)**.\n        `null` means open-ended end.\n    - **isShownBeforePeriod** (boolean, required) - Whether the bonus is exposed\n      to players before `timeRange.from`.\n    - **isShownAfterPeriod** (boolean, required) - Whether the bonus is exposed\n      after `timeRange.to`.\n    - **shownBeforePeriodMinutes** (long, optional) - How long before\n      `timeRange.from` the bonus becomes visible.\n    - **shownAfterPeriodMinutes** (long, optional) - How long after\n      `timeRange.to` the bonus remains visible.\n  - **timeSchedule** (object, optional) - Recurring activity schedule.\n    Polymorphic on `__payloadKind`:\n    - `HoursOfDayTimeSchedule` — recurring hours-of-day periods (`periods`).\n    - `DaysOfWeekTimeSchedule` — recurring per-day-of-week periods\n      (`periodsByDay`).\n    - `DaysOfMonthTimeSchedule` — recurring per-day-of-month periods\n      (`periodsByDay`).\n\n    `null` when activity is window-only.\n\n  Outside the window the bonus is unclaimable (Sumstats responds with\n  `BONUS_NOT_AVAILABLE` (303) on claim).\n\n- **timeForActivationInHours** (integer, optional) - Hours after claim during which\n  the player must activate the bonus (i.e. how long the `CLAIMED → IN_PROGRESS`\n  transition is allowed). `null` = unlimited (the player bonus stays in `CLAIMED`\n  until activation or manual cancel). Used by Sumstats to compute `expiredOnClaimAt`\n  on the resulting player bonus. Example: `168` means the player has seven days to\n  activate.\n\n- **currencies** (array of strings, required) - Currencies the bonus supports\n  (ISO 4217 codes — `TRY`, `EUR`, `USD`, …). The bonus can only be claimed by players\n  whose account currency is in this set. In Mode 2, only bonuses whose `currencies`\n  array contains the player's currency are returned. Empty array indicates a\n  misconfiguration on the operator side.\n\n- **isAutoActivates** (boolean, required) - When `true`, the bonus auto-activates on\n  claim — partners do **not** need to call `activate-player-bonus`. The\n  `claim-bonus-for-player` response carries `status: \"IN_PROGRESS\"` and a populated\n  `activatedAt`. When `false`, the partner must explicitly call `activate-player-bonus`\n  within `timeForActivationInHours` hours, or the player bonus expires.\n\n- **bonusSize** (object, required) - Substantive offer payload describing the\n  free-bet rule and amount. **For `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind`\n  is always `\"FreeBetSize\"`.** See **FreeBetSize** below.\n\n- **winSize** (object, optional) - Cap on potential winnings. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — the substantive limits are encoded inside the\n  free-bet criteria (`bonusSize.rule.productRules[].criteria.maxWinAllowed`).\n\n- **wagering** (object, optional) - Wagering rules. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — free bets do not have a turnover requirement; the\n  free bet either wins, loses, or expires per the criteria rules.\n\n### `bonusSize` — FreeBetSize\n\nFor `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind = \"FreeBetSize\"`. The\n`FreeBetSize` payload has two top-level fields:\n\n- **rule** (object, required) - The free-bet rule — defines per-product criteria,\n  free-bet use type, and validity. See **FreeBetRule** below.\n- **amount** (object, optional) - Total monetary value handed to the player as a\n  free-bet balance when the bonus is activated. Polymorphic on `__payloadKind`. Two\n  practical kinds for free bets:\n\n  - **MonetarySize** - Fixed amount.\n\n    - **money** (MoneyBag, required) - The free-bet balance. See **MoneyBag** below.\n\n  - **PercentageSize** - Percentage of a baseline (rare for free bets).\n\n    - **percentage** (number, required) - Percentage value, e.g. `100.0` = 100%.\n    - **maxAmount** (MoneyBag, optional) - Upper cap on the resulting balance.\n    - **minAmount** (MoneyBag, optional) - Lower floor on the resulting balance.\n\n### `bonusSize.rule` — FreeBetRule\n\n**Object:**\n\n- **productRules** (array of `FreeBetProductRule`, required, length ≥ 1) - Per-product\n  free-bet criteria. **For sportsbook free bets there is a single entry with\n  `product: \"SPORTS\"`.**\n\n  Each `FreeBetProductRule` has:\n\n  - **note** (array of `{locale, translate}`, optional) - Operator-supplied note\n    describing the rule, localised. `null` when no note was set.\n  - **title** (array of `{locale, translate}`, optional) - Operator-supplied title\n    for the rule, localised. `null` when no title was set.\n  - **product** (string, required) - For this integration's scope, always `\"SPORTS\"`.\n  - **criteria** (object, required) - Per-product limit rules. Polymorphic on\n    `__payloadKind`. **For sportsbook free bets,\n    `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.** See\n    **InternalFreeBetSportsbookCriteria** below.\n\n- **validityInHours** (integer, required) - Lifetime of the *activated* bonus, in\n  hours. `0` = unlimited (the bonus runs until the free-bet balance is exhausted,\n  the bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\n  Used by Sumstats to compute `expiredAt` on the activated player bonus.\n\n- **note** (array of `{locale, translate}`, optional) - Free-form operator note for\n  the rule as a whole, localised. `null` when no note was set.\n\n- **freeBetUseType** (object, required) - How the free-bet money composes the\n  player's stake. Polymorphic on `__payloadKind`. See **FreeBetUseType union** below.\n\n### `criteria` — InternalFreeBetSportsbookCriteria\n\nFor sportsbook free bets, `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.\nTop-level fields:\n\n- **filters** (array of `InternalFreeBetSportsbookFilter`, required) - Filter list\n  narrowing where the free bet may be staked. **An empty filter list means \"no\n  narrowing\"** (the free bet may be staked on any sportsbook event). Multiple filters\n  are OR'd: a stake is allowed if **at least one** filter accepts it. See\n  **InternalFreeBetSportsbookFilter** below.\n\n- **minValue** (MoneyBag, optional) - Minimum bet stake required. `null` = no\n  minimum. Stakes below this are rejected by the bet placement engine.\n\n- **maxValue** (MoneyBag, optional) - Maximum bet stake allowed. `null` = no\n  maximum. Stakes above this are rejected.\n\n- **maxWinAllowed** (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\n  single free-bet stake are capped at this amount. `null` = no cap (free bet pays\n  out the full computed winnings).\n\n- **maxAmountOfBets** (integer, optional) - Maximum number of bets the player may\n  place using the free-bet balance. `null` = unlimited (the bonus runs until the\n  free-bet balance is exhausted or expires). Once the limit is hit, the bonus\n  transitions to `COMPLETED` automatically.\n\n#### `filters[]` — InternalFreeBetSportsbookFilter\n\nNarrows the events on which the free bet may be staked. **All scalar fields are\nnullable; `null` means \"no restriction on this dimension\".** The filter accepts a\nstake when *every* set field matches the stake's event metadata:\n\n- **sportId** (string, optional) - Restrict to a specific sport (UUID, operator-defined\n  — e.g. football, basketball, tennis). `null` = any sport.\n\n- **categoryId** (string, optional) - Restrict to a category — typically a country /\n  region inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n  `null` = any category.\n\n- **tournamentId** (string, optional) - Restrict to a tournament inside a category\n  (UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). `null` = any\n  tournament.\n\n- **eventId** (string, optional) - Restrict to a single event / match (UUID,\n  operator-defined). `null` = any event.\n\n- **markets** (array of `MarketType`, required) - Allow-listed market identifiers\n  from the generated `MarketType` enum (lowercase enum names from the SportsbookSchema).\n  Examples: `score_1x2`, `score_ou`, `score_dc`, `score_both_to_score_yes_no`,\n  `score_ht_ft`, `score_winning_margin`, `score_exact_number`, `corner_1x2`,\n  `yellow_card_1x2`. **Empty array means any market.**\n\n- **betRule** (object, optional) - Bet-shape restrictions. **All `betRule` fields\n  are nullable; `null` (or empty for set-typed fields) means \"no restriction on this\n  dimension\".** A stake is accepted when every set field matches.\n\n  - **betTypes** (array of `BetHashType`, required) - Allowed bet types from the\n    `BetHashType` enum. The JSON wire form is **lowercase** (set by Jackson\n    `@JsonProperty` on the enum). Possible values:\n\n    - `single` - A single selection bet.\n    - `parlay` - Accumulator bet (multiple selections combined; all must win).\n      The `accumulator*` betRule fields below apply only to this bet type.\n    - `system` - System bet (combinations of accumulators).\n\n    **Empty array means any bet type.**\n\n  - **live** (boolean, optional) - `true` = live betting only, `false` = pre-match\n    only, `null` = both allowed.\n  - **singleMinOdd** (number, optional) - Minimum odd for `single` bets. Ignored\n    for non-single bet types. Applied to the bet's single odd at placement time.\n  - **accumulatorTotalOdds** (number, optional) - Minimum total odds for a `parlay`\n    (the product of all selection odds). Ignored for non-`parlay` bet types.\n  - **accumulatorAtLeastOdd** (number, optional) - At least one selection in the\n    `parlay` must have an odd ≥ this value. Combined with\n    `accumulatorMinOddPerSelection` for fine-grained control.\n  - **accumulatorMinNumberOfSelections** (integer, optional) - Minimum number of\n    legs (selections) in the `parlay`.\n  - **accumulatorMaxNumberOfSelections** (integer, optional) - Maximum number of\n    legs in the `parlay`.\n  - **accumulatorMinOddPerSelection** (number, optional) - Minimum odd that\n    **every** selection in the `parlay` must meet.\n\n### `freeBetUseType` — FreeBetUseType union\n\nDiscriminated by `__payloadKind`. Two concrete kinds:\n\n- **`FreeBetAllBalanceUseType`** - The stake must consist 100% of free-bet money. Real\n  money cannot be mixed in.\n\n  - **isMustBeStakedAtOnce** (boolean, required) - When `true`, the entire free-bet\n    balance must be wagered in a **single** bet (the player cannot split the\n    balance across multiple bets). When `false`, the player may place multiple bets\n    until the balance is exhausted, subject to `maxAmountOfBets`.\n\n- **`FreeBetPartialBalanceUseType`** - The stake may mix free-bet money with real\n  money. Each bet's free-bet portion is bounded.\n\n  - **minValue** (MoneyBag, optional) - Minimum free-bet amount per bet. `null` =\n    no minimum.\n  - **maxValue** (MoneyBag, optional) - Maximum free-bet amount per bet. `null` =\n    no maximum.\n\n### `MoneyBag`\n\nShape — examples in this document use only the `system` amount in a single currency:\n\n```json\n{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n```\n\n- **system** (`{amount, currency}`, required) - The amount in the bonus's currency.\n  The `amount` is a **string** (decimal with no implied scaling — the bonus engine\n  stores monetary values in raw integer minor-unit form, e.g. `\"50000\"` = 500.00 TRY).\n- **additional** (array, required) - Per-currency overrides for cross-currency\n  bonuses. When the player's currency matches an entry's `currency`, the entry's\n  `amount` is used directly; otherwise the `system` amount is converted via the\n  operator's currency-pair rates. Single-currency bonuses (the common case) emit\n  an empty array, as in all examples in this document.\n\n## Request Examples\n\n### Mode 1 — Catalogue lookup\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true\n}\n```\n\n### Mode 2 — Available bonuses for a specific player\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n```\n\n### Mode 3 — Registration bonuses only\n\n```json\n{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)\n\nThe faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n**Demonstrates the unrestricted shape:** `filters[0]` has every dimension `null` /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). `freeBetUseType` is `FreeBetAllBalanceUseType` with\n`isMustBeStakedAtOnce: true`, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Internal Free Bet (populated sportsbook)\n\nA 100 TRY free bet for **Premier League pre-match singles and parlays**.\n**Demonstrates every populated dimension using real SportsbookSchema values:**\n\n- Sport / category / tournament gating: `sportId` (Football),\n  `categoryId` (England), `tournamentId` (Premier League).\n- Three real `MarketType` values allow-listed:\n  `[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]`.\n- `betTypes: [\"single\", \"parlay\"]` — uses real `BetHashType` JSON values\n  (lowercase via Jackson `@JsonProperty`).\n- `live: false` — pre-match only.\n- `single` bets must have an odd ≥ `1.5`.\n- `parlay` bets must have total odds ≥ `3.0`, between `3` and `10` selections, every\n  selection at min odd `1.2`, with at least one selection at min odd `1.3`.\n- Stake band `25 TRY ≤ stake ≤ 100 TRY`, max win `1000 TRY`, max `5` bets.\n- 72-hour validity once activated.\n- `freeBetUseType` is `FreeBetPartialBalanceUseType` with the same `25-100 TRY` bounds\n  per bet — meaning the player may combine free-bet money with real money on the\n  same stake.\n- `isAutoActivates: false` — the partner must call `activate-player-bonus` after\n  claim.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty result\n\n```json\n{\n    \"bonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- Both `available` and `tag` omitted.\n- `tag` provided but not equal to `\"REGISTRATION\"` (case-insensitive).\n- Malformed `brandId` (non-integer) or missing `Authorization`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\nOccurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nOccurs in Mode 2 when the `externalUserId` cannot be resolved or registered\nautomatically.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\nOccurs when `Authorization` is missing, malformed, or does not match a known brand\ncredential.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 403 Forbidden - IP not whitelisted\n\nOccurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.\n\n**Example Error Response (HTML body, status 403):**\n\n```text\nIP <client-ip> is not presented in white list\n```\n\n### 500 Internal Server Error - Unknown Error\n\nOccurs when an unexpected server error happens.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Sportsbook free-bet only.** This integration is purpose-built for\n   `INTERNAL_FREE_BET` bonuses on the sportsbook product\n   (`InternalFreeBetSportsbookCriteria` payload). `winSize` is always `null`,\n   `wagering` is always `null`. All limits and rules are encoded inside\n   `bonusSize.rule.productRules[].criteria` and `bonusSize.rule.freeBetUseType`. Other\n   `bonusType` values and non-sportsbook free-bet criteria may appear in the catalogue\n   and should be filtered out client-side.\n\n2. **Real schema values.** `betRule.betTypes` uses the **`BetHashType`** enum with\n   lowercase JSON values (`\"single\"`, `\"parlay\"`, `\"system\"`) — the `parlay` value is\n   the schema name for accumulator bets. `markets` uses the **`MarketType`** enum\n   from the generated SportsbookSchema (lowercase names like `score_1x2`, `score_ou`,\n   `score_both_to_score_yes_no`).\n\n3. **Visibility flag handling.** In Mode 1 (catalogue) the operator-side\n   `\"Show For Players\"` visibility flag is ignored — partners see the full enabled\n   catalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n   `isShownForPlayers: false` are hidden.\n\n4. **Mode 2 player registration side-effect.** When `externalUserId` is unknown to\n   Sumstats, the system attempts to register the player automatically before\n   evaluating eligibility. Subsequent calls for the same `externalUserId` skip\n   this step. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n5. **Polymorphic `__payloadKind` discriminator.** All polymorphic objects\n   (`bonusSize`, `criteria`, `freeBetUseType`, `bonusSize.amount`) carry a\n   `__payloadKind` field containing the concrete payload kind. Partners must\n   discriminate on this field — adding new payload kinds in the future is the\n   standard evolution path.\n\n6. **`MoneyBag.system` semantics.** `system` carries the canonical amount in the\n   operator's accounting currency. When the player's currency matches an entry in\n   `additional`, that override is used directly; otherwise the system entry is\n   converted via the operator's currency-pair rates. Partners should prefer the\n   `additional` entry matching the player's currency for display.\n\n7. **Currencies and bonus selection.** The `currencies` array on the bonus is the\n   set of currencies the bonus supports. In Mode 2, only bonuses whose `currencies`\n   array contains the player's currency are returned.\n\n8. **Empty filter list semantics.** `criteria.filters` is an array — an **empty\n   array** means \"no narrowing\": the free bet may be staked on any sportsbook event.\n   **A non-empty filter list is OR'd:** a stake is allowed when at least one filter\n   accepts it.\n\n9. **Empty-vs-null in `betRule`.** `betRule.betTypes: []` and `betRule.markets: []`\n   mean \"any\" (no restriction); `betRule.live: null` means \"any live mode\"; numeric /\n   integer fields use `null` for \"no restriction\". The semantics differ — empty array\n   on `betTypes` / `markets`, `null` on the rest.\n\n10. **`isAutoActivates` impact on the claim flow.** When `isAutoActivates: true`,\n    calling `claim-bonus-for-player` immediately moves the player bonus to\n    `IN_PROGRESS`. When `false`, the partner must call `activate-player-bonus` within\n    `timeForActivationInHours` hours.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}"},{"id":"ebe219cf-6478-4e69-8f16-725384b4f1e1","name":"fail — invalid user","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"available\": true,\n    \"externalUserId\": \"ext_987654321\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-available-bonuses","description":"# Endpoint for Finding Available Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-available-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet bonuses** currently offered\nby the operator. Three usage modes are selected via the request body fields:\n\n- **Mode 1 — All available bonuses (catalogue).** `available: true`, `externalUserId`\n  omitted. Returns all enabled, in-activity-window bonuses. The operator-side\n  `\"Show For Players\"` visibility flag is **ignored** in this mode — the full catalogue\n  is exposed so the partner can plan campaigns.\n- **Mode 2 — Available bonuses for a specific player.** `available: true`,\n  `externalUserId` set. Returns only the bonuses available *for that player*: per-player\n  limits, claim eligibility rules and the operator-side visibility flag are honoured,\n  and bonuses already claimed/active for the player are excluded. If the external\n  player is unknown to Sumstats, the system attempts to register them automatically\n  before evaluating eligibility.\n- **Mode 3 — Registration bonuses only.** `tag: \"REGISTRATION\"` (with or without\n  `available`). Returns the subset of bonuses tagged for new-player registration flows.\n\nThe response is **not paginated** — the operator catalogue is bounded (typically tens to\nlow hundreds of enabled bonuses). Each bonus carries a polymorphic free-bet payload\n(`bonusSize.__payloadKind = \"FreeBetSize\"`) describing the substantive offer; the\npartner is expected to discriminate on `__payloadKind` for nested polymorphic objects\n(`criteria`, `freeBetUseType`, `bonusSize.amount`).\n\n> **Scope.** This integration is purpose-built for `INTERNAL_FREE_BET` bonuses on the\n> sportsbook product (`InternalFreeBetSportsbookCriteria` payload). Other bonus types\n> (`CUSTOM`, `FIRST_DEPOSIT`, `EXTERNAL_FREE_BET`, `EXTERNAL_FREE_SPINS_WITH_WAGERING`,\n> `INTERNAL_FREE_SPINS_WITH_WAGERING`, `CASHBACK`) and non-sportsbook free-bet\n> criteria may exist in the operator catalogue but are out of scope for this contract — partners should filter the response to\n> `bonusType: \"INTERNAL_FREE_BET\"` with\n> `bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"`\n> client-side.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the brand\n  encoded in the HTTP Basic credentials. Used together with `Authorization` for\n  credential lookup.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only — partners on the new contract must send `brandId`.\n\n- **available** (boolean, optional) - When `true` activates Mode 1 or Mode 2 selection.\n  When omitted, `tag` must be set, otherwise the request is rejected with\n  `BAD_REQUEST`.\n\n- **externalUserId** (string, optional) - External player id in the operator system.\n  When set, switches the call to Mode 2 (per-player filtering). If the player is\n  unknown to Sumstats, the system attempts to register them automatically.\n\n- **tag** (string, optional) - When set, must be `\"REGISTRATION\"` (case-insensitive)\n  and switches the call to Mode 3. Any other value is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **bonuses** (array of objects, required) - List of bonus objects matching the query.\n  Empty list when nothing matches. The partner-facing slim shape drops\n  internal/operational fields (`descriptionTitle`, `descriptionBonusRules`,\n  `fullTermsAndConditions`, `descriptionFiles`, `isShownForPlayers`, `bonusTags`,\n  `shareLimitsId`, `eligibilityClaimRulesCompletionInfo`, `notSatisfiedMatchResults`,\n  `satisfiedMatchResults`, `operatorId`, `ruleIds`, `removedAt`, `updatedAt`,\n  `playerGroupIds`, `bonusOverridableFeatures`).\n\n  Each bonus object has the structure documented under **Bonus Fields** below.\n\n### Bonus Fields\n\nThe slim partner-facing bonus shape. Field-by-field semantics:\n\n- **id** (string, required) - Bonus identifier in **UUID v7** format. This is the\n  *catalogue* id of the bonus configuration, not a per-player id. Pass to\n  `claim-bonus-for-player`, `activate-player-bonus`, `cancel-player-bonus`. Stable\n  across partner calls — repeated `find-available-bonuses` requests return the same\n  `id` for the same operator-configured bonus until the operator deletes the\n  configuration.\n\n- **name** (array of `{locale, translate}`, required) - Localised bonus names. Each\n  entry binds a `locale` (BCP-47 / ICU locale code, e.g. `en_US`, `de_DE`) to\n  the human-readable bonus name in that locale. Partners should pick the entry\n  matching the player's locale; when no exact match exists, fall back to `en_US` or\n  the first entry. Bonuses are guaranteed to have **at least one** translation\n  (typically `en_US`).\n\n- **bonusType** (enum, required) - High-level bonus kind. **For this integration's\n  contract, the relevant value is `INTERNAL_FREE_BET`.** Drives which payload shapes\n  appear inside `bonusSize`. Other types may appear in the catalogue but are out of\n  scope — partners should filter the response to `bonusType: \"INTERNAL_FREE_BET\"`\n  client-side.\n\n- **status** (enum, required) - Lifecycle status of the bonus on the operator side.\n  Possible values:\n\n  - `NOT_STARTED` - Created and saved but the activity window has not started yet.\n  - `SCHEDULED` - Inside the configured activity window but the bonus is scheduled to go active at a later point.\n  - `ACTIVE` - Enabled and inside the activity window. Only `ACTIVE` bonuses can be claimed.\n  - `DISABLED` - Operator switched the bonus off from the admin panel.\n  - `EXPIRED` - Activity window has passed.\n  - `REMOVED` - Operator deleted the bonus configuration. Catalogue audits only — not claimable.\n\n  Only `ACTIVE` bonuses can be claimed — `find-available-bonuses` does not return\n  non-`ACTIVE` bonuses by default; the field is informational for catalogue audits.\n\n- **enabled** (boolean, required) - `false` when the operator has explicitly disabled\n  the bonus from the admin panel. A bonus with `status: ACTIVE` and `enabled: false`\n  is unavailable for new claims and will not appear in Mode 2 (per-player) responses.\n  Mode 1 (catalogue) responses include disabled bonuses for partner audit purposes.\n\n- **promotionCode** (string, optional) - Operator-issued promotion code (e.g.\n  `\"500TRYFREEBET\"`, `\"EPL100\"`). When set, the bonus is gated by the code on the\n  player-facing surface — players can only claim it through a promo-code flow.\n  `null` when the bonus is freely claimable. **Partners using this integration claim\n  by `bonusId` directly and bypass the promo-code gate**, but the field is exposed\n  so partners can mirror operator-side promo flows on their UI.\n\n- **activityTime** (object, optional) - Activity window. `null` means always on\n  (no time gate). The shape mirrors the internal `ActivityTime` record — at most\n  one of `timePeriod` / `timeSchedule` is populated:\n\n  - **timePeriod** (object, optional) - Continuous activity window.\n    - **timeRange** (object, required) - Half-open period.\n      - **from** (long, optional) - Start of the window in **epoch millis (UTC)**.\n        `null` means open-ended start.\n      - **to** (long, optional) - End of the window in **epoch millis (UTC)**.\n        `null` means open-ended end.\n    - **isShownBeforePeriod** (boolean, required) - Whether the bonus is exposed\n      to players before `timeRange.from`.\n    - **isShownAfterPeriod** (boolean, required) - Whether the bonus is exposed\n      after `timeRange.to`.\n    - **shownBeforePeriodMinutes** (long, optional) - How long before\n      `timeRange.from` the bonus becomes visible.\n    - **shownAfterPeriodMinutes** (long, optional) - How long after\n      `timeRange.to` the bonus remains visible.\n  - **timeSchedule** (object, optional) - Recurring activity schedule.\n    Polymorphic on `__payloadKind`:\n    - `HoursOfDayTimeSchedule` — recurring hours-of-day periods (`periods`).\n    - `DaysOfWeekTimeSchedule` — recurring per-day-of-week periods\n      (`periodsByDay`).\n    - `DaysOfMonthTimeSchedule` — recurring per-day-of-month periods\n      (`periodsByDay`).\n\n    `null` when activity is window-only.\n\n  Outside the window the bonus is unclaimable (Sumstats responds with\n  `BONUS_NOT_AVAILABLE` (303) on claim).\n\n- **timeForActivationInHours** (integer, optional) - Hours after claim during which\n  the player must activate the bonus (i.e. how long the `CLAIMED → IN_PROGRESS`\n  transition is allowed). `null` = unlimited (the player bonus stays in `CLAIMED`\n  until activation or manual cancel). Used by Sumstats to compute `expiredOnClaimAt`\n  on the resulting player bonus. Example: `168` means the player has seven days to\n  activate.\n\n- **currencies** (array of strings, required) - Currencies the bonus supports\n  (ISO 4217 codes — `TRY`, `EUR`, `USD`, …). The bonus can only be claimed by players\n  whose account currency is in this set. In Mode 2, only bonuses whose `currencies`\n  array contains the player's currency are returned. Empty array indicates a\n  misconfiguration on the operator side.\n\n- **isAutoActivates** (boolean, required) - When `true`, the bonus auto-activates on\n  claim — partners do **not** need to call `activate-player-bonus`. The\n  `claim-bonus-for-player` response carries `status: \"IN_PROGRESS\"` and a populated\n  `activatedAt`. When `false`, the partner must explicitly call `activate-player-bonus`\n  within `timeForActivationInHours` hours, or the player bonus expires.\n\n- **bonusSize** (object, required) - Substantive offer payload describing the\n  free-bet rule and amount. **For `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind`\n  is always `\"FreeBetSize\"`.** See **FreeBetSize** below.\n\n- **winSize** (object, optional) - Cap on potential winnings. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — the substantive limits are encoded inside the\n  free-bet criteria (`bonusSize.rule.productRules[].criteria.maxWinAllowed`).\n\n- **wagering** (object, optional) - Wagering rules. **Always `null` for\n  `INTERNAL_FREE_BET` bonuses** — free bets do not have a turnover requirement; the\n  free bet either wins, loses, or expires per the criteria rules.\n\n### `bonusSize` — FreeBetSize\n\nFor `INTERNAL_FREE_BET` bonuses, `bonusSize.__payloadKind = \"FreeBetSize\"`. The\n`FreeBetSize` payload has two top-level fields:\n\n- **rule** (object, required) - The free-bet rule — defines per-product criteria,\n  free-bet use type, and validity. See **FreeBetRule** below.\n- **amount** (object, optional) - Total monetary value handed to the player as a\n  free-bet balance when the bonus is activated. Polymorphic on `__payloadKind`. Two\n  practical kinds for free bets:\n\n  - **MonetarySize** - Fixed amount.\n\n    - **money** (MoneyBag, required) - The free-bet balance. See **MoneyBag** below.\n\n  - **PercentageSize** - Percentage of a baseline (rare for free bets).\n\n    - **percentage** (number, required) - Percentage value, e.g. `100.0` = 100%.\n    - **maxAmount** (MoneyBag, optional) - Upper cap on the resulting balance.\n    - **minAmount** (MoneyBag, optional) - Lower floor on the resulting balance.\n\n### `bonusSize.rule` — FreeBetRule\n\n**Object:**\n\n- **productRules** (array of `FreeBetProductRule`, required, length ≥ 1) - Per-product\n  free-bet criteria. **For sportsbook free bets there is a single entry with\n  `product: \"SPORTS\"`.**\n\n  Each `FreeBetProductRule` has:\n\n  - **note** (array of `{locale, translate}`, optional) - Operator-supplied note\n    describing the rule, localised. `null` when no note was set.\n  - **title** (array of `{locale, translate}`, optional) - Operator-supplied title\n    for the rule, localised. `null` when no title was set.\n  - **product** (string, required) - For this integration's scope, always `\"SPORTS\"`.\n  - **criteria** (object, required) - Per-product limit rules. Polymorphic on\n    `__payloadKind`. **For sportsbook free bets,\n    `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.** See\n    **InternalFreeBetSportsbookCriteria** below.\n\n- **validityInHours** (integer, required) - Lifetime of the *activated* bonus, in\n  hours. `0` = unlimited (the bonus runs until the free-bet balance is exhausted,\n  the bet limit hits, or the operator cancels). Maximum supported value ≈ 1 month.\n  Used by Sumstats to compute `expiredAt` on the activated player bonus.\n\n- **note** (array of `{locale, translate}`, optional) - Free-form operator note for\n  the rule as a whole, localised. `null` when no note was set.\n\n- **freeBetUseType** (object, required) - How the free-bet money composes the\n  player's stake. Polymorphic on `__payloadKind`. See **FreeBetUseType union** below.\n\n### `criteria` — InternalFreeBetSportsbookCriteria\n\nFor sportsbook free bets, `criteria.__payloadKind = \"InternalFreeBetSportsbookCriteria\"`.\nTop-level fields:\n\n- **filters** (array of `InternalFreeBetSportsbookFilter`, required) - Filter list\n  narrowing where the free bet may be staked. **An empty filter list means \"no\n  narrowing\"** (the free bet may be staked on any sportsbook event). Multiple filters\n  are OR'd: a stake is allowed if **at least one** filter accepts it. See\n  **InternalFreeBetSportsbookFilter** below.\n\n- **minValue** (MoneyBag, optional) - Minimum bet stake required. `null` = no\n  minimum. Stakes below this are rejected by the bet placement engine.\n\n- **maxValue** (MoneyBag, optional) - Maximum bet stake allowed. `null` = no\n  maximum. Stakes above this are rejected.\n\n- **maxWinAllowed** (MoneyBag, optional) - Per-bet win cap. When set, winnings on a\n  single free-bet stake are capped at this amount. `null` = no cap (free bet pays\n  out the full computed winnings).\n\n- **maxAmountOfBets** (integer, optional) - Maximum number of bets the player may\n  place using the free-bet balance. `null` = unlimited (the bonus runs until the\n  free-bet balance is exhausted or expires). Once the limit is hit, the bonus\n  transitions to `COMPLETED` automatically.\n\n#### `filters[]` — InternalFreeBetSportsbookFilter\n\nNarrows the events on which the free bet may be staked. **All scalar fields are\nnullable; `null` means \"no restriction on this dimension\".** The filter accepts a\nstake when *every* set field matches the stake's event metadata:\n\n- **sportId** (string, optional) - Restrict to a specific sport (UUID, operator-defined\n  — e.g. football, basketball, tennis). `null` = any sport.\n\n- **categoryId** (string, optional) - Restrict to a category — typically a country /\n  region inside a sport (UUID, operator-defined — e.g. England, Germany, ATP Tour).\n  `null` = any category.\n\n- **tournamentId** (string, optional) - Restrict to a tournament inside a category\n  (UUID, operator-defined — e.g. Premier League, Bundesliga, Wimbledon). `null` = any\n  tournament.\n\n- **eventId** (string, optional) - Restrict to a single event / match (UUID,\n  operator-defined). `null` = any event.\n\n- **markets** (array of `MarketType`, required) - Allow-listed market identifiers\n  from the generated `MarketType` enum (lowercase enum names from the SportsbookSchema).\n  Examples: `score_1x2`, `score_ou`, `score_dc`, `score_both_to_score_yes_no`,\n  `score_ht_ft`, `score_winning_margin`, `score_exact_number`, `corner_1x2`,\n  `yellow_card_1x2`. **Empty array means any market.**\n\n- **betRule** (object, optional) - Bet-shape restrictions. **All `betRule` fields\n  are nullable; `null` (or empty for set-typed fields) means \"no restriction on this\n  dimension\".** A stake is accepted when every set field matches.\n\n  - **betTypes** (array of `BetHashType`, required) - Allowed bet types from the\n    `BetHashType` enum. The JSON wire form is **lowercase** (set by Jackson\n    `@JsonProperty` on the enum). Possible values:\n\n    - `single` - A single selection bet.\n    - `parlay` - Accumulator bet (multiple selections combined; all must win).\n      The `accumulator*` betRule fields below apply only to this bet type.\n    - `system` - System bet (combinations of accumulators).\n\n    **Empty array means any bet type.**\n\n  - **live** (boolean, optional) - `true` = live betting only, `false` = pre-match\n    only, `null` = both allowed.\n  - **singleMinOdd** (number, optional) - Minimum odd for `single` bets. Ignored\n    for non-single bet types. Applied to the bet's single odd at placement time.\n  - **accumulatorTotalOdds** (number, optional) - Minimum total odds for a `parlay`\n    (the product of all selection odds). Ignored for non-`parlay` bet types.\n  - **accumulatorAtLeastOdd** (number, optional) - At least one selection in the\n    `parlay` must have an odd ≥ this value. Combined with\n    `accumulatorMinOddPerSelection` for fine-grained control.\n  - **accumulatorMinNumberOfSelections** (integer, optional) - Minimum number of\n    legs (selections) in the `parlay`.\n  - **accumulatorMaxNumberOfSelections** (integer, optional) - Maximum number of\n    legs in the `parlay`.\n  - **accumulatorMinOddPerSelection** (number, optional) - Minimum odd that\n    **every** selection in the `parlay` must meet.\n\n### `freeBetUseType` — FreeBetUseType union\n\nDiscriminated by `__payloadKind`. Two concrete kinds:\n\n- **`FreeBetAllBalanceUseType`** - The stake must consist 100% of free-bet money. Real\n  money cannot be mixed in.\n\n  - **isMustBeStakedAtOnce** (boolean, required) - When `true`, the entire free-bet\n    balance must be wagered in a **single** bet (the player cannot split the\n    balance across multiple bets). When `false`, the player may place multiple bets\n    until the balance is exhausted, subject to `maxAmountOfBets`.\n\n- **`FreeBetPartialBalanceUseType`** - The stake may mix free-bet money with real\n  money. Each bet's free-bet portion is bounded.\n\n  - **minValue** (MoneyBag, optional) - Minimum free-bet amount per bet. `null` =\n    no minimum.\n  - **maxValue** (MoneyBag, optional) - Maximum free-bet amount per bet. `null` =\n    no maximum.\n\n### `MoneyBag`\n\nShape — examples in this document use only the `system` amount in a single currency:\n\n```json\n{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n```\n\n- **system** (`{amount, currency}`, required) - The amount in the bonus's currency.\n  The `amount` is a **string** (decimal with no implied scaling — the bonus engine\n  stores monetary values in raw integer minor-unit form, e.g. `\"50000\"` = 500.00 TRY).\n- **additional** (array, required) - Per-currency overrides for cross-currency\n  bonuses. When the player's currency matches an entry's `currency`, the entry's\n  `amount` is used directly; otherwise the `system` amount is converted via the\n  operator's currency-pair rates. Single-currency bonuses (the common case) emit\n  an empty array, as in all examples in this document.\n\n## Request Examples\n\n### Mode 1 — Catalogue lookup\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true\n}\n```\n\n### Mode 2 — Available bonuses for a specific player\n\n```json\n{\n  \"brandId\": 0,\n  \"available\": true,\n  \"externalUserId\": \"ext_987654321\"\n}\n```\n\n### Mode 3 — Registration bonuses only\n\n```json\n{\n  \"brandId\": 0,\n  \"tag\": \"REGISTRATION\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Internal Free Bet (minimal sportsbook)\n\nThe faithful \"500 TRY FREE BET\" bonus from the legacy Bonus API documentation.\n**Demonstrates the unrestricted shape:** `filters[0]` has every dimension `null` /\nempty (any sport, any category, any tournament, any event, any market, any bet type,\nany odds, no selection limits). `freeBetUseType` is `FreeBetAllBalanceUseType` with\n`isMustBeStakedAtOnce: true`, meaning the entire 500 TRY balance must be wagered in a\nsingle bet.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"500TRYFREEBET\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 168,\n            \"currencies\": [\n                \"TRY\",\n                \"EUR\"\n            ],\n            \"isAutoActivates\": true,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": null,\n                            \"title\": null,\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": null,\n                                        \"categoryId\": null,\n                                        \"tournamentId\": null,\n                                        \"eventId\": null,\n                                        \"markets\": [],\n                                        \"betRule\": {\n                                            \"betTypes\": [],\n                                            \"live\": null,\n                                            \"singleMinOdd\": null,\n                                            \"accumulatorTotalOdds\": null,\n                                            \"accumulatorAtLeastOdd\": null,\n                                            \"accumulatorMinNumberOfSelections\": null,\n                                            \"accumulatorMinOddPerSelection\": null,\n                                            \"accumulatorMaxNumberOfSelections\": null\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"50000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": null,\n                                \"maxAmountOfBets\": null\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 168,\n                    \"note\": null,\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetAllBalanceUseType\",\n                        \"isMustBeStakedAtOnce\": true\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"50000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Internal Free Bet (populated sportsbook)\n\nA 100 TRY free bet for **Premier League pre-match singles and parlays**.\n**Demonstrates every populated dimension using real SportsbookSchema values:**\n\n- Sport / category / tournament gating: `sportId` (Football),\n  `categoryId` (England), `tournamentId` (Premier League).\n- Three real `MarketType` values allow-listed:\n  `[\"score_1x2\", \"score_ou\", \"score_both_to_score_yes_no\"]`.\n- `betTypes: [\"single\", \"parlay\"]` — uses real `BetHashType` JSON values\n  (lowercase via Jackson `@JsonProperty`).\n- `live: false` — pre-match only.\n- `single` bets must have an odd ≥ `1.5`.\n- `parlay` bets must have total odds ≥ `3.0`, between `3` and `10` selections, every\n  selection at min odd `1.2`, with at least one selection at min odd `1.3`.\n- Stake band `25 TRY ≤ stake ≤ 100 TRY`, max win `1000 TRY`, max `5` bets.\n- 72-hour validity once activated.\n- `freeBetUseType` is `FreeBetPartialBalanceUseType` with the same `25-100 TRY` bounds\n  per bet — meaning the player may combine free-bet money with real money on the\n  same stake.\n- `isAutoActivates: false` — the partner must call `activate-player-bonus` after\n  claim.\n\n```json\n{\n    \"bonuses\": [\n        {\n            \"id\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"name\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"ACTIVE\",\n            \"enabled\": true,\n            \"promotionCode\": \"EPL100\",\n            \"activityTime\": {\n                \"timePeriod\": {\n                    \"timeRange\": {\n                        \"from\": 1761721205143,\n                        \"to\": 1764313205143\n                    },\n                    \"isShownBeforePeriod\": true,\n                    \"isShownAfterPeriod\": false,\n                    \"shownBeforePeriodMinutes\": null,\n                    \"shownAfterPeriodMinutes\": null\n                },\n                \"timeSchedule\": null\n            },\n            \"timeForActivationInHours\": 72,\n            \"currencies\": [\n                \"TRY\"\n            ],\n            \"isAutoActivates\": false,\n            \"bonusSize\": {\n                \"__payloadKind\": \"FreeBetSize\",\n                \"rule\": {\n                    \"productRules\": [\n                        {\n                            \"note\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League pre-match singles and parlays only.\"\n                                }\n                            ],\n                            \"title\": [\n                                {\n                                    \"locale\": \"en_US\",\n                                    \"translate\": \"Premier League Free Bet\"\n                                }\n                            ],\n                            \"criteria\": {\n                                \"__payloadKind\": \"InternalFreeBetSportsbookCriteria\",\n                                \"filters\": [\n                                    {\n                                        \"sportId\": \"0192aaaa-1111-7000-9000-000000000001\",\n                                        \"categoryId\": \"0192aaaa-1111-7000-9000-000000000002\",\n                                        \"tournamentId\": \"0192aaaa-1111-7000-9000-000000000003\",\n                                        \"eventId\": null,\n                                        \"markets\": [\n                                            \"score_1x2\",\n                                            \"score_ou\",\n                                            \"score_both_to_score_yes_no\"\n                                        ],\n                                        \"betRule\": {\n                                            \"betTypes\": [\n                                                \"single\",\n                                                \"parlay\"\n                                            ],\n                                            \"live\": false,\n                                            \"singleMinOdd\": 1.5,\n                                            \"accumulatorTotalOdds\": 3.0,\n                                            \"accumulatorAtLeastOdd\": 1.3,\n                                            \"accumulatorMinNumberOfSelections\": 3,\n                                            \"accumulatorMinOddPerSelection\": 1.2,\n                                            \"accumulatorMaxNumberOfSelections\": 10\n                                        }\n                                    }\n                                ],\n                                \"minValue\": {\n                                    \"system\": {\n                                        \"amount\": \"2500\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxValue\": {\n                                    \"system\": {\n                                        \"amount\": \"10000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxWinAllowed\": {\n                                    \"system\": {\n                                        \"amount\": \"100000\",\n                                        \"currency\": \"TRY\"\n                                    },\n                                    \"additional\": []\n                                },\n                                \"maxAmountOfBets\": 5\n                            },\n                            \"product\": \"SPORTS\"\n                        }\n                    ],\n                    \"validityInHours\": 72,\n                    \"note\": [\n                        {\n                            \"locale\": \"en_US\",\n                            \"translate\": \"Pre-match Premier League free bet \\u2014 5 bets max within 72h.\"\n                        }\n                    ],\n                    \"freeBetUseType\": {\n                        \"__payloadKind\": \"FreeBetPartialBalanceUseType\",\n                        \"minValue\": {\n                            \"system\": {\n                                \"amount\": \"2500\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        },\n                        \"maxValue\": {\n                            \"system\": {\n                                \"amount\": \"10000\",\n                                \"currency\": \"TRY\"\n                            },\n                            \"additional\": []\n                        }\n                    }\n                },\n                \"amount\": {\n                    \"__payloadKind\": \"MonetarySize\",\n                    \"money\": {\n                        \"system\": {\n                            \"amount\": \"10000\",\n                            \"currency\": \"TRY\"\n                        },\n                        \"additional\": []\n                    }\n                }\n            },\n            \"winSize\": null,\n            \"wagering\": null\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty result\n\n```json\n{\n    \"bonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- Both `available` and `tag` omitted.\n- `tag` provided but not equal to `\"REGISTRATION\"` (case-insensitive).\n- Malformed `brandId` (non-integer) or missing `Authorization`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"either 'available=true' or 'tag=REGISTRATION' must be supplied\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\nOccurs when the JSON body cannot be parsed (truncated, invalid escapes, etc.).\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nOccurs in Mode 2 when the `externalUserId` cannot be resolved or registered\nautomatically.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\nOccurs when `Authorization` is missing, malformed, or does not match a known brand\ncredential.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 403 Forbidden - IP not whitelisted\n\nOccurs when the request originates from an IP not present in the per-brand allow\nlist. Returned by the gateway, before the application is hit.\n\n**Example Error Response (HTML body, status 403):**\n\n```text\nIP <client-ip> is not presented in white list\n```\n\n### 500 Internal Server Error - Unknown Error\n\nOccurs when an unexpected server error happens.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Sportsbook free-bet only.** This integration is purpose-built for\n   `INTERNAL_FREE_BET` bonuses on the sportsbook product\n   (`InternalFreeBetSportsbookCriteria` payload). `winSize` is always `null`,\n   `wagering` is always `null`. All limits and rules are encoded inside\n   `bonusSize.rule.productRules[].criteria` and `bonusSize.rule.freeBetUseType`. Other\n   `bonusType` values and non-sportsbook free-bet criteria may appear in the catalogue\n   and should be filtered out client-side.\n\n2. **Real schema values.** `betRule.betTypes` uses the **`BetHashType`** enum with\n   lowercase JSON values (`\"single\"`, `\"parlay\"`, `\"system\"`) — the `parlay` value is\n   the schema name for accumulator bets. `markets` uses the **`MarketType`** enum\n   from the generated SportsbookSchema (lowercase names like `score_1x2`, `score_ou`,\n   `score_both_to_score_yes_no`).\n\n3. **Visibility flag handling.** In Mode 1 (catalogue) the operator-side\n   `\"Show For Players\"` visibility flag is ignored — partners see the full enabled\n   catalogue. In Mode 2 (per-player) the flag is honoured: bonuses with\n   `isShownForPlayers: false` are hidden.\n\n4. **Mode 2 player registration side-effect.** When `externalUserId` is unknown to\n   Sumstats, the system attempts to register the player automatically before\n   evaluating eligibility. Subsequent calls for the same `externalUserId` skip\n   this step. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n5. **Polymorphic `__payloadKind` discriminator.** All polymorphic objects\n   (`bonusSize`, `criteria`, `freeBetUseType`, `bonusSize.amount`) carry a\n   `__payloadKind` field containing the concrete payload kind. Partners must\n   discriminate on this field — adding new payload kinds in the future is the\n   standard evolution path.\n\n6. **`MoneyBag.system` semantics.** `system` carries the canonical amount in the\n   operator's accounting currency. When the player's currency matches an entry in\n   `additional`, that override is used directly; otherwise the system entry is\n   converted via the operator's currency-pair rates. Partners should prefer the\n   `additional` entry matching the player's currency for display.\n\n7. **Currencies and bonus selection.** The `currencies` array on the bonus is the\n   set of currencies the bonus supports. In Mode 2, only bonuses whose `currencies`\n   array contains the player's currency are returned.\n\n8. **Empty filter list semantics.** `criteria.filters` is an array — an **empty\n   array** means \"no narrowing\": the free bet may be staked on any sportsbook event.\n   **A non-empty filter list is OR'd:** a stake is allowed when at least one filter\n   accepts it.\n\n9. **Empty-vs-null in `betRule`.** `betRule.betTypes: []` and `betRule.markets: []`\n   mean \"any\" (no restriction); `betRule.live: null` means \"any live mode\"; numeric /\n   integer fields use `null` for \"no restriction\". The semantics differ — empty array\n   on `betTypes` / `markets`, `null` on the rest.\n\n10. **`isAutoActivates` impact on the claim flow.** When `isAutoActivates: true`,\n    calling `claim-bonus-for-player` immediately moves the player bonus to\n    `IN_PROGRESS`. When `false`, the partner must call `activate-player-bonus` within\n    `timeForActivationInHours` hours.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}"}],"_postman_id":"ff735f49-0e6f-44aa-9cbd-5de8c0a13051"},{"name":"Find Player Bonuses","id":"e44ffde8-9b83-40a8-bfb8-63fe00dc6985","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"statuses\": [\n        \"CLAIMED\",\n        \"IN_PROGRESS\"\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-player-bonuses","description":"<h1 id=\"endpoint-for-finding-player-bonuses\">Endpoint for Finding Player Bonuses</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/bonus/find-player-bonuses</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint returns the <strong>internal sportsbook free-bet</strong> player bonuses currently<br />associated with a given external player, filtered by status. Use it to determine<br />whether a player has any active or completed free-bet bonuses before deciding whether<br />to offer a new claim, to drive a \"My Bonuses\" surface on the partner side, or to<br />reconcile partner-side bookkeeping with Sumstats's record.</p>\n<p>The response is <strong>not paginated</strong> — partners typically hold ≤ a few dozen player<br />bonuses at a time per player.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by Sumstats. Must match the<br />  brand encoded in the HTTP Basic credentials.</p>\n</li>\n<li><p><strong>brand</strong> (string, optional) - Deprecated alias for <code>brandId</code>. Accepted during the<br />  brand migration window only.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - External player id in the operator system.<br />  Resolved automatically if unknown to Sumstats.</p>\n</li>\n<li><p><strong>statuses</strong> (array of strings, required, length ≥ 1) - Status filter. The result<br />  contains player bonuses whose current status is <strong>any</strong> of the values in this array<br />  (OR semantics, equivalent to a SQL <code>IN</code> clause). Possible values:</p>\n<ul>\n<li><p><code>CLAIMED</code> - Player bonus is created but not yet activated. Only reachable for<br />  bonuses where <code>isAutoActivates: false</code> — the player has not yet received a<br />  free-bet balance.</p>\n</li>\n<li><p><code>IN_PROGRESS</code> - Active player bonus. The player has a free-bet balance and is<br />  placing bets towards completion.</p>\n</li>\n<li><p><code>WON</code> - Wagering bonus finished with a positive outcome and the player was<br />  rewarded the win amount. Reachable for wagering-style bonuses (e.g. <code>CUSTOM</code>,<br />  <code>FIRST_DEPOSIT</code>, <code>\\*_FREE_SPINS_WITH_WAGERING</code>) that may surface via legacy<br />  paths. Pure <code>INTERNAL_FREE_BET</code> bonuses settle directly through the bet<br />  engine and typically transition to <code>COMPLETED</code> / <code>LOST</code> instead.</p>\n</li>\n<li><p><code>COMPLETED</code> - The player exhausted the free-bet balance (or hit<br />  <code>maxAmountOfBets</code>) and the bonus is finished.</p>\n</li>\n<li><p><code>CANCELLED</code> - Operator (or this integration) explicitly cancelled the player<br />  bonus. <code>finishedAt</code> is set to the cancellation timestamp.</p>\n</li>\n<li><p><code>EXPIRED</code> - The bonus's claim window or activity window passed before the<br />  player exhausted the balance. <code>expiredAt</code> / <code>expiredOnClaimAt</code> is set.</p>\n</li>\n<li><p><code>LOST</code> - All free-bet stakes settled as losses (and <code>maxAmountOfBets</code> was hit<br />  or the validity expired with no winning stakes).</p>\n</li>\n</ul>\n<p>  Empty array is rejected with <code>BAD_REQUEST</code>.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>playerBonuses</strong> (array of objects, required) - List of player bonus objects<br />  matching the status filter. Empty list when nothing matches.</p>\n<p>  Each player bonus object has the structure documented under <strong>Player Bonus Fields</strong><br />  below.</p>\n</li>\n</ul>\n<h3 id=\"player-bonus-fields\">Player Bonus Fields</h3>\n<p>The slim partner-facing player-bonus shape. Internal fields dropped: <code>tinyId</code>,<br /><code>playerId</code>, <code>snapshotVersion</code>, the heavy <code>bonusSnapshot</code> (replaced by <code>bonusId</code> +<br /><code>bonusName</code> + <code>bonusType</code>), operator overrides (<code>overriddenBonusAmount</code>,<br /><code>overriddenDepositAmount</code>, <code>overriddenFreeSpinsCount</code>, <code>overriddenWinAmount</code>,<br /><code>wonGiven</code>), <code>heldDepositSum</code>, <code>wageringProductsProgress[]</code>,<br /><code>freeBetProductsProgress[]</code>, and <code>updatedAt</code>.</p>\n<p>Field-by-field semantics:</p>\n<ul>\n<li><p><strong>id</strong> (string, required) - Player-bonus identifier (UUID v7). <strong>Store this for****reconciliation.</strong> Distinct from <code>bonusId</code> — the <code>id</code> is unique per claim, while<br />  <code>bonusId</code> is shared across all players who claimed the same catalogue bonus.</p>\n</li>\n<li><p><strong>bonusId</strong> (string, required) - Underlying bonus id (UUID v7). Refers back to<br />  the bonus catalogue entry returned by <code>find-available-bonuses</code>. Use this to fetch<br />  the catalogue-side rules / criteria when needed.</p>\n</li>\n<li><p><strong>bonusName</strong> (array of <code>{locale, translate}</code>, required) - Localised bonus names<br />  captured at claim time. <strong>Snapshot — does not reflect later catalogue edits.</strong><br />  Partners should pick the entry matching the player's locale and fall back to<br />  <code>en_US</code> when no exact match exists.</p>\n</li>\n<li><p><strong>bonusType</strong> (enum, required) - Captured <code>bonusType</code> of the underlying bonus.<br />  For this integration's contract, expect <code>INTERNAL_FREE_BET</code>. Other types may<br />  surface if the player previously claimed via legacy paths.</p>\n</li>\n<li><p><strong>status</strong> (enum, required) - Current player-bonus status. See the list of<br />  possible values above in the request <code>statuses</code> field documentation.</p>\n</li>\n<li><p><strong>externalPlayerId</strong> (string, optional) - Echo of the partner-side user id<br />  supplied at claim. <code>null</code> for player bonuses created via internal flows (e.g.<br />  legacy admin panel, VIP-club rewards).</p>\n</li>\n<li><p><strong>createdAt</strong> (long, required) - Created-at timestamp (<strong>epoch millis, UTC</strong>)<br />  when the player bonus was claimed.</p>\n</li>\n<li><p><strong>activatedAt</strong> (long, optional) - Activated-at timestamp (epoch millis, UTC).<br />  <code>null</code> while still <code>CLAIMED</code>. For auto-activating bonuses, equals <code>createdAt + Δ</code><br />  where Δ is small (the activation event is committed immediately after the claim<br />  event).</p>\n</li>\n<li><p><strong>finishedAt</strong> (long, optional) - Finished-at timestamp (epoch millis, UTC).<br />  <code>null</code> while the bonus is <code>CLAIMED</code> or <code>IN_PROGRESS</code>. Set when <code>status</code> becomes<br />  <code>COMPLETED</code>, <code>CANCELLED</code>, <code>EXPIRED</code>, or <code>LOST</code>.</p>\n</li>\n<li><p><strong>expiredAt</strong> (long, optional) - Expiry timestamp (epoch millis, UTC) for the<br />  <code>IN_PROGRESS</code> window. <code>null</code> for unlimited bonuses (<code>validityInHours: 0</code> on the<br />  rule). Computed as <code>activatedAt + rule.validityInHours × 3600 × 1000</code>.</p>\n</li>\n<li><p><strong>expiredOnClaimAt</strong> (long, optional) - Expiry timestamp (epoch millis, UTC) for<br />  the <code>CLAIMED</code> activation window — i.e. when the player must call activate by.<br />  <code>null</code> after the bonus has been activated. Computed as <code>createdAt +   timeForActivationInHours × 3600 × 1000</code>.</p>\n</li>\n<li><p><strong>isAutoActivates</strong> (boolean, required) - Snapshot of the catalogue-side flag at<br />  claim time. Drives whether the partner needs to call <code>activate-player-bonus</code>.</p>\n</li>\n<li><p><strong>bonusGiven</strong> (object, optional) - Awarded <strong>free-bet balance</strong> in the player's<br />  currency. <code>null</code> while <code>CLAIMED</code> (no money has been credited yet). Once the<br />  bonus is <code>IN_PROGRESS</code>, this reflects the original awarded balance — it does<br />  <strong>not</strong> decrement as the player places bets (use the bonus wallet balance API<br />  to track real-time consumption).</p>\n<ul>\n<li><p><strong>amount</strong> (string, required) - Amount in raw integer minor-unit form (e.g.<br />  <code>\"50000\"</code> = 500.00 TRY).</p>\n</li>\n<li><p><strong>currency</strong> (string, required) - Currency code, ISO 4217.</p>\n</li>\n</ul>\n</li>\n<li><p><strong>totalWagering</strong> (object, optional) - <strong>Always</strong> <strong><code>null</code></strong> <strong>for</strong> <strong><code>INTERNAL_FREE_BET</code></strong><br />  — free bets do not have a turnover requirement. Present only for player bonuses<br />  created from non-free-bet catalogue entries that may surface via legacy paths.</p>\n<ul>\n<li><p><strong>amount</strong> (string, required) - Amount in raw integer minor-unit form.</p>\n</li>\n<li><p><strong>currency</strong> (string, required) - Currency code.</p>\n</li>\n</ul>\n</li>\n<li><p><strong>currency</strong> (string, required) - Currency the bonus was issued in. Matches the<br />  player's currency at claim time. If the player later switches currency, the<br />  existing player bonus retains its original <code>currency</code>.</p>\n</li>\n</ul>\n<h2 id=\"request-examples\">Request Examples</h2>\n<h3 id=\"active-player-bonuses\">Active player bonuses</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"CLAIMED\", \"IN_PROGRESS\"]\n}\n\n</code></pre>\n<h3 id=\"terminal-player-bonuses-history-view\">Terminal player bonuses (history view)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"COMPLETED\", \"CANCELLED\", \"EXPIRED\", \"LOST\"]\n}\n\n</code></pre>\n<h3 id=\"single-status-query\">Single-status query</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"IN_PROGRESS\"]\n}\n\n</code></pre>\n<h2 id=\"response-examples\">Response Examples</h2>\n<h3 id=\"successful-response-200-ok--active-free-bet-player-bonuses\">Successful Response (200 OK) — Active free-bet player bonuses</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}\n\n</code></pre>\n<h3 id=\"successful-response-200-ok--empty-list\">Successful Response (200 OK) — Empty list</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonuses\": []\n}\n\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li><p><code>statuses</code> array is empty.</p>\n</li>\n<li><p><code>statuses</code> contains a value that is not a known <code>PlayerBonusStatus</code>.</p>\n</li>\n<li><p><code>externalUserId</code> is blank.</p>\n</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---deserialization-error\">400 Bad Request - Deserialization Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n\n</code></pre>\n<h3 id=\"401-unauthorized---invalid-credentials\">401 Unauthorized - Invalid Credentials</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Slim shape.</strong> Money fields are projected to plain <code>{amount, currency}</code> in the<br /> player's currency — partners do not need the <code>MoneyTransaction</code> system / external<br /> / currency-pair scaffolding the internal model carries.</p>\n</li>\n<li><p><strong>Status filter is OR.</strong> Multiple values in <code>statuses</code> produce a result containing<br /> bonuses whose current status is <strong>any</strong> of the values.</p>\n</li>\n<li><p><strong>Result ordering.</strong> Result is sorted by <code>createdAt</code> descending (most recent<br /> first). Partners that need a stable order should sort client-side on <code>id</code>.</p>\n</li>\n<li><p><strong>Currency.</strong> A player bonus is always denominated in a single currency, captured<br /> at claim time. If the player later switches currency, existing player bonuses<br /> retain their original <code>currency</code>.</p>\n</li>\n<li><p><strong><code>bonusGiven</code></strong> <strong>does not decrement.</strong> <code>bonusGiven</code> reflects the <strong>original****awarded balance</strong> — it does not track real-time consumption as the player places<br /> bets. To observe live free-bet wallet balance, use the bonus-wallet APIs.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires HTTP Basic authentication. Per-brand credentials are issued by<br />Sumstats Support and configured via the operator dashboard. Calls also pass an IP<br />whitelist — requests originating outside the allow-listed IPs are rejected at the<br />gateway with HTTP 403.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Basic base64(username:password)\nContent-Type: application/json\n\n</code></pre>\n<p>Use the <code>brandId</code> body field together with the credentials — Sumstats resolves the brand<br />from the credentials and validates that the request <code>brandId</code> matches.</p>\n","urlObject":{"path":["external-casino-client","v1","bonus","find-player-bonuses"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"b28ddb19-edf6-45f0-9119-799beebbb1ae","name":"success — Active free-bet player bonuses","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"statuses\": [\n        \"CLAIMED\",\n        \"IN_PROGRESS\"\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-player-bonuses","description":"# Endpoint for Finding Player Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-player-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet** player bonuses currently\nassociated with a given external player, filtered by status. Use it to determine\nwhether a player has any active or completed free-bet bonuses before deciding whether\nto offer a new claim, to drive a \"My Bonuses\" surface on the partner side, or to\nreconcile partner-side bookkeeping with Sumstats's record.\n\nThe response is **not paginated** — partners typically hold ≤ a few dozen player\nbonuses at a time per player.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats.\n\n- **statuses** (array of strings, required, length ≥ 1) - Status filter. The result\n  contains player bonuses whose current status is **any** of the values in this array\n  (OR semantics, equivalent to a SQL `IN` clause). Possible values:\n\n  - `CLAIMED` - Player bonus is created but not yet activated. Only reachable for\n    bonuses where `isAutoActivates: false` — the player has not yet received a\n    free-bet balance.\n  - `IN_PROGRESS` - Active player bonus. The player has a free-bet balance and is\n    placing bets towards completion.\n  - `WON` - Wagering bonus finished with a positive outcome and the player was\n    rewarded the win amount. Reachable for wagering-style bonuses (e.g. `CUSTOM`,\n    `FIRST_DEPOSIT`, `*_FREE_SPINS_WITH_WAGERING`) that may surface via legacy\n    paths. Pure `INTERNAL_FREE_BET` bonuses settle directly through the bet\n    engine and typically transition to `COMPLETED` / `LOST` instead.\n  - `COMPLETED` - The player exhausted the free-bet balance (or hit\n    `maxAmountOfBets`) and the bonus is finished.\n  - `CANCELLED` - Operator (or this integration) explicitly cancelled the player\n    bonus. `finishedAt` is set to the cancellation timestamp.\n  - `EXPIRED` - The bonus's claim window or activity window passed before the\n    player exhausted the balance. `expiredAt` / `expiredOnClaimAt` is set.\n  - `LOST` - All free-bet stakes settled as losses (and `maxAmountOfBets` was hit\n    or the validity expired with no winning stakes).\n\n  Empty array is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonuses** (array of objects, required) - List of player bonus objects\n  matching the status filter. Empty list when nothing matches.\n\n  Each player bonus object has the structure documented under **Player Bonus Fields**\n  below.\n\n### Player Bonus Fields\n\nThe slim partner-facing player-bonus shape. Internal fields dropped: `tinyId`,\n`playerId`, `snapshotVersion`, the heavy `bonusSnapshot` (replaced by `bonusId` +\n`bonusName` + `bonusType`), operator overrides (`overriddenBonusAmount`,\n`overriddenDepositAmount`, `overriddenFreeSpinsCount`, `overriddenWinAmount`,\n`wonGiven`), `heldDepositSum`, `wageringProductsProgress[]`,\n`freeBetProductsProgress[]`, and `updatedAt`.\n\nField-by-field semantics:\n\n- **id** (string, required) - Player-bonus identifier (UUID v7). **Store this for\n  reconciliation.** Distinct from `bonusId` — the `id` is unique per claim, while\n  `bonusId` is shared across all players who claimed the same catalogue bonus.\n\n- **bonusId** (string, required) - Underlying bonus id (UUID v7). Refers back to\n  the bonus catalogue entry returned by `find-available-bonuses`. Use this to fetch\n  the catalogue-side rules / criteria when needed.\n\n- **bonusName** (array of `{locale, translate}`, required) - Localised bonus names\n  captured at claim time. **Snapshot — does not reflect later catalogue edits.**\n  Partners should pick the entry matching the player's locale and fall back to\n  `en_US` when no exact match exists.\n\n- **bonusType** (enum, required) - Captured `bonusType` of the underlying bonus.\n  For this integration's contract, expect `INTERNAL_FREE_BET`. Other types may\n  surface if the player previously claimed via legacy paths.\n\n- **status** (enum, required) - Current player-bonus status. See the list of\n  possible values above in the request `statuses` field documentation.\n\n- **externalPlayerId** (string, optional) - Echo of the partner-side user id\n  supplied at claim. `null` for player bonuses created via internal flows (e.g.\n  legacy admin panel, VIP-club rewards).\n\n- **createdAt** (long, required) - Created-at timestamp (**epoch millis, UTC**)\n  when the player bonus was claimed.\n\n- **activatedAt** (long, optional) - Activated-at timestamp (epoch millis, UTC).\n  `null` while still `CLAIMED`. For auto-activating bonuses, equals `createdAt + Δ`\n  where Δ is small (the activation event is committed immediately after the claim\n  event).\n\n- **finishedAt** (long, optional) - Finished-at timestamp (epoch millis, UTC).\n  `null` while the bonus is `CLAIMED` or `IN_PROGRESS`. Set when `status` becomes\n  `COMPLETED`, `CANCELLED`, `EXPIRED`, or `LOST`.\n\n- **expiredAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for the\n  `IN_PROGRESS` window. `null` for unlimited bonuses (`validityInHours: 0` on the\n  rule). Computed as `activatedAt + rule.validityInHours × 3600 × 1000`.\n\n- **expiredOnClaimAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for\n  the `CLAIMED` activation window — i.e. when the player must call activate by.\n  `null` after the bonus has been activated. Computed as `createdAt +\n  timeForActivationInHours × 3600 × 1000`.\n\n- **isAutoActivates** (boolean, required) - Snapshot of the catalogue-side flag at\n  claim time. Drives whether the partner needs to call `activate-player-bonus`.\n\n- **bonusGiven** (object, optional) - Awarded **free-bet balance** in the player's\n  currency. `null` while `CLAIMED` (no money has been credited yet). Once the\n  bonus is `IN_PROGRESS`, this reflects the original awarded balance — it does\n  **not** decrement as the player places bets (use the bonus wallet balance API\n  to track real-time consumption).\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form (e.g.\n    `\"50000\"` = 500.00 TRY).\n  - **currency** (string, required) - Currency code, ISO 4217.\n\n- **totalWagering** (object, optional) - **Always `null` for `INTERNAL_FREE_BET`**\n  — free bets do not have a turnover requirement. Present only for player bonuses\n  created from non-free-bet catalogue entries that may surface via legacy paths.\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form.\n  - **currency** (string, required) - Currency code.\n\n- **currency** (string, required) - Currency the bonus was issued in. Matches the\n  player's currency at claim time. If the player later switches currency, the\n  existing player bonus retains its original `currency`.\n\n## Request Examples\n\n### Active player bonuses\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"CLAIMED\", \"IN_PROGRESS\"]\n}\n```\n\n### Terminal player bonuses (history view)\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"COMPLETED\", \"CANCELLED\", \"EXPIRED\", \"LOST\"]\n}\n```\n\n### Single-status query\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"IN_PROGRESS\"]\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Active free-bet player bonuses\n\n```json\n{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty list\n\n```json\n{\n    \"playerBonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `statuses` array is empty.\n- `statuses` contains a value that is not a known `PlayerBonusStatus`.\n- `externalUserId` is blank.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Slim shape.** Money fields are projected to plain `{amount, currency}` in the\n   player's currency — partners do not need the `MoneyTransaction` system / external\n   / currency-pair scaffolding the internal model carries.\n\n2. **Status filter is OR.** Multiple values in `statuses` produce a result containing\n   bonuses whose current status is **any** of the values.\n\n3. **Result ordering.** Result is sorted by `createdAt` descending (most recent\n   first). Partners that need a stable order should sort client-side on `id`.\n\n4. **Currency.** A player bonus is always denominated in a single currency, captured\n   at claim time. If the player later switches currency, existing player bonuses\n   retain their original `currency`.\n\n5. **`bonusGiven` does not decrement.** `bonusGiven` reflects the **original\n   awarded balance** — it does not track real-time consumption as the player places\n   bets. To observe live free-bet wallet balance, use the bonus-wallet APIs.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}"},{"id":"0998925a-65ac-4223-990c-afef90b3f98f","name":"success — Empty","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"statuses\": [\n        \"CLAIMED\",\n        \"IN_PROGRESS\"\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-player-bonuses","description":"# Endpoint for Finding Player Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-player-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet** player bonuses currently\nassociated with a given external player, filtered by status. Use it to determine\nwhether a player has any active or completed free-bet bonuses before deciding whether\nto offer a new claim, to drive a \"My Bonuses\" surface on the partner side, or to\nreconcile partner-side bookkeeping with Sumstats's record.\n\nThe response is **not paginated** — partners typically hold ≤ a few dozen player\nbonuses at a time per player.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats.\n\n- **statuses** (array of strings, required, length ≥ 1) - Status filter. The result\n  contains player bonuses whose current status is **any** of the values in this array\n  (OR semantics, equivalent to a SQL `IN` clause). Possible values:\n\n  - `CLAIMED` - Player bonus is created but not yet activated. Only reachable for\n    bonuses where `isAutoActivates: false` — the player has not yet received a\n    free-bet balance.\n  - `IN_PROGRESS` - Active player bonus. The player has a free-bet balance and is\n    placing bets towards completion.\n  - `WON` - Wagering bonus finished with a positive outcome and the player was\n    rewarded the win amount. Reachable for wagering-style bonuses (e.g. `CUSTOM`,\n    `FIRST_DEPOSIT`, `*_FREE_SPINS_WITH_WAGERING`) that may surface via legacy\n    paths. Pure `INTERNAL_FREE_BET` bonuses settle directly through the bet\n    engine and typically transition to `COMPLETED` / `LOST` instead.\n  - `COMPLETED` - The player exhausted the free-bet balance (or hit\n    `maxAmountOfBets`) and the bonus is finished.\n  - `CANCELLED` - Operator (or this integration) explicitly cancelled the player\n    bonus. `finishedAt` is set to the cancellation timestamp.\n  - `EXPIRED` - The bonus's claim window or activity window passed before the\n    player exhausted the balance. `expiredAt` / `expiredOnClaimAt` is set.\n  - `LOST` - All free-bet stakes settled as losses (and `maxAmountOfBets` was hit\n    or the validity expired with no winning stakes).\n\n  Empty array is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonuses** (array of objects, required) - List of player bonus objects\n  matching the status filter. Empty list when nothing matches.\n\n  Each player bonus object has the structure documented under **Player Bonus Fields**\n  below.\n\n### Player Bonus Fields\n\nThe slim partner-facing player-bonus shape. Internal fields dropped: `tinyId`,\n`playerId`, `snapshotVersion`, the heavy `bonusSnapshot` (replaced by `bonusId` +\n`bonusName` + `bonusType`), operator overrides (`overriddenBonusAmount`,\n`overriddenDepositAmount`, `overriddenFreeSpinsCount`, `overriddenWinAmount`,\n`wonGiven`), `heldDepositSum`, `wageringProductsProgress[]`,\n`freeBetProductsProgress[]`, and `updatedAt`.\n\nField-by-field semantics:\n\n- **id** (string, required) - Player-bonus identifier (UUID v7). **Store this for\n  reconciliation.** Distinct from `bonusId` — the `id` is unique per claim, while\n  `bonusId` is shared across all players who claimed the same catalogue bonus.\n\n- **bonusId** (string, required) - Underlying bonus id (UUID v7). Refers back to\n  the bonus catalogue entry returned by `find-available-bonuses`. Use this to fetch\n  the catalogue-side rules / criteria when needed.\n\n- **bonusName** (array of `{locale, translate}`, required) - Localised bonus names\n  captured at claim time. **Snapshot — does not reflect later catalogue edits.**\n  Partners should pick the entry matching the player's locale and fall back to\n  `en_US` when no exact match exists.\n\n- **bonusType** (enum, required) - Captured `bonusType` of the underlying bonus.\n  For this integration's contract, expect `INTERNAL_FREE_BET`. Other types may\n  surface if the player previously claimed via legacy paths.\n\n- **status** (enum, required) - Current player-bonus status. See the list of\n  possible values above in the request `statuses` field documentation.\n\n- **externalPlayerId** (string, optional) - Echo of the partner-side user id\n  supplied at claim. `null` for player bonuses created via internal flows (e.g.\n  legacy admin panel, VIP-club rewards).\n\n- **createdAt** (long, required) - Created-at timestamp (**epoch millis, UTC**)\n  when the player bonus was claimed.\n\n- **activatedAt** (long, optional) - Activated-at timestamp (epoch millis, UTC).\n  `null` while still `CLAIMED`. For auto-activating bonuses, equals `createdAt + Δ`\n  where Δ is small (the activation event is committed immediately after the claim\n  event).\n\n- **finishedAt** (long, optional) - Finished-at timestamp (epoch millis, UTC).\n  `null` while the bonus is `CLAIMED` or `IN_PROGRESS`. Set when `status` becomes\n  `COMPLETED`, `CANCELLED`, `EXPIRED`, or `LOST`.\n\n- **expiredAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for the\n  `IN_PROGRESS` window. `null` for unlimited bonuses (`validityInHours: 0` on the\n  rule). Computed as `activatedAt + rule.validityInHours × 3600 × 1000`.\n\n- **expiredOnClaimAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for\n  the `CLAIMED` activation window — i.e. when the player must call activate by.\n  `null` after the bonus has been activated. Computed as `createdAt +\n  timeForActivationInHours × 3600 × 1000`.\n\n- **isAutoActivates** (boolean, required) - Snapshot of the catalogue-side flag at\n  claim time. Drives whether the partner needs to call `activate-player-bonus`.\n\n- **bonusGiven** (object, optional) - Awarded **free-bet balance** in the player's\n  currency. `null` while `CLAIMED` (no money has been credited yet). Once the\n  bonus is `IN_PROGRESS`, this reflects the original awarded balance — it does\n  **not** decrement as the player places bets (use the bonus wallet balance API\n  to track real-time consumption).\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form (e.g.\n    `\"50000\"` = 500.00 TRY).\n  - **currency** (string, required) - Currency code, ISO 4217.\n\n- **totalWagering** (object, optional) - **Always `null` for `INTERNAL_FREE_BET`**\n  — free bets do not have a turnover requirement. Present only for player bonuses\n  created from non-free-bet catalogue entries that may surface via legacy paths.\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form.\n  - **currency** (string, required) - Currency code.\n\n- **currency** (string, required) - Currency the bonus was issued in. Matches the\n  player's currency at claim time. If the player later switches currency, the\n  existing player bonus retains its original `currency`.\n\n## Request Examples\n\n### Active player bonuses\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"CLAIMED\", \"IN_PROGRESS\"]\n}\n```\n\n### Terminal player bonuses (history view)\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"COMPLETED\", \"CANCELLED\", \"EXPIRED\", \"LOST\"]\n}\n```\n\n### Single-status query\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"IN_PROGRESS\"]\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Active free-bet player bonuses\n\n```json\n{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty list\n\n```json\n{\n    \"playerBonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `statuses` array is empty.\n- `statuses` contains a value that is not a known `PlayerBonusStatus`.\n- `externalUserId` is blank.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Slim shape.** Money fields are projected to plain `{amount, currency}` in the\n   player's currency — partners do not need the `MoneyTransaction` system / external\n   / currency-pair scaffolding the internal model carries.\n\n2. **Status filter is OR.** Multiple values in `statuses` produce a result containing\n   bonuses whose current status is **any** of the values.\n\n3. **Result ordering.** Result is sorted by `createdAt` descending (most recent\n   first). Partners that need a stable order should sort client-side on `id`.\n\n4. **Currency.** A player bonus is always denominated in a single currency, captured\n   at claim time. If the player later switches currency, existing player bonuses\n   retain their original `currency`.\n\n5. **`bonusGiven` does not decrement.** `bonusGiven` reflects the **original\n   awarded balance** — it does not track real-time consumption as the player places\n   bets. To observe live free-bet wallet balance, use the bonus-wallet APIs.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonuses\": []\n}"},{"id":"4a80aec6-19c2-4ba2-82c7-037cb694f139","name":"fail — empty statuses","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"statuses\": [\n        \"CLAIMED\",\n        \"IN_PROGRESS\"\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-player-bonuses","description":"# Endpoint for Finding Player Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-player-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet** player bonuses currently\nassociated with a given external player, filtered by status. Use it to determine\nwhether a player has any active or completed free-bet bonuses before deciding whether\nto offer a new claim, to drive a \"My Bonuses\" surface on the partner side, or to\nreconcile partner-side bookkeeping with Sumstats's record.\n\nThe response is **not paginated** — partners typically hold ≤ a few dozen player\nbonuses at a time per player.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats.\n\n- **statuses** (array of strings, required, length ≥ 1) - Status filter. The result\n  contains player bonuses whose current status is **any** of the values in this array\n  (OR semantics, equivalent to a SQL `IN` clause). Possible values:\n\n  - `CLAIMED` - Player bonus is created but not yet activated. Only reachable for\n    bonuses where `isAutoActivates: false` — the player has not yet received a\n    free-bet balance.\n  - `IN_PROGRESS` - Active player bonus. The player has a free-bet balance and is\n    placing bets towards completion.\n  - `WON` - Wagering bonus finished with a positive outcome and the player was\n    rewarded the win amount. Reachable for wagering-style bonuses (e.g. `CUSTOM`,\n    `FIRST_DEPOSIT`, `*_FREE_SPINS_WITH_WAGERING`) that may surface via legacy\n    paths. Pure `INTERNAL_FREE_BET` bonuses settle directly through the bet\n    engine and typically transition to `COMPLETED` / `LOST` instead.\n  - `COMPLETED` - The player exhausted the free-bet balance (or hit\n    `maxAmountOfBets`) and the bonus is finished.\n  - `CANCELLED` - Operator (or this integration) explicitly cancelled the player\n    bonus. `finishedAt` is set to the cancellation timestamp.\n  - `EXPIRED` - The bonus's claim window or activity window passed before the\n    player exhausted the balance. `expiredAt` / `expiredOnClaimAt` is set.\n  - `LOST` - All free-bet stakes settled as losses (and `maxAmountOfBets` was hit\n    or the validity expired with no winning stakes).\n\n  Empty array is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonuses** (array of objects, required) - List of player bonus objects\n  matching the status filter. Empty list when nothing matches.\n\n  Each player bonus object has the structure documented under **Player Bonus Fields**\n  below.\n\n### Player Bonus Fields\n\nThe slim partner-facing player-bonus shape. Internal fields dropped: `tinyId`,\n`playerId`, `snapshotVersion`, the heavy `bonusSnapshot` (replaced by `bonusId` +\n`bonusName` + `bonusType`), operator overrides (`overriddenBonusAmount`,\n`overriddenDepositAmount`, `overriddenFreeSpinsCount`, `overriddenWinAmount`,\n`wonGiven`), `heldDepositSum`, `wageringProductsProgress[]`,\n`freeBetProductsProgress[]`, and `updatedAt`.\n\nField-by-field semantics:\n\n- **id** (string, required) - Player-bonus identifier (UUID v7). **Store this for\n  reconciliation.** Distinct from `bonusId` — the `id` is unique per claim, while\n  `bonusId` is shared across all players who claimed the same catalogue bonus.\n\n- **bonusId** (string, required) - Underlying bonus id (UUID v7). Refers back to\n  the bonus catalogue entry returned by `find-available-bonuses`. Use this to fetch\n  the catalogue-side rules / criteria when needed.\n\n- **bonusName** (array of `{locale, translate}`, required) - Localised bonus names\n  captured at claim time. **Snapshot — does not reflect later catalogue edits.**\n  Partners should pick the entry matching the player's locale and fall back to\n  `en_US` when no exact match exists.\n\n- **bonusType** (enum, required) - Captured `bonusType` of the underlying bonus.\n  For this integration's contract, expect `INTERNAL_FREE_BET`. Other types may\n  surface if the player previously claimed via legacy paths.\n\n- **status** (enum, required) - Current player-bonus status. See the list of\n  possible values above in the request `statuses` field documentation.\n\n- **externalPlayerId** (string, optional) - Echo of the partner-side user id\n  supplied at claim. `null` for player bonuses created via internal flows (e.g.\n  legacy admin panel, VIP-club rewards).\n\n- **createdAt** (long, required) - Created-at timestamp (**epoch millis, UTC**)\n  when the player bonus was claimed.\n\n- **activatedAt** (long, optional) - Activated-at timestamp (epoch millis, UTC).\n  `null` while still `CLAIMED`. For auto-activating bonuses, equals `createdAt + Δ`\n  where Δ is small (the activation event is committed immediately after the claim\n  event).\n\n- **finishedAt** (long, optional) - Finished-at timestamp (epoch millis, UTC).\n  `null` while the bonus is `CLAIMED` or `IN_PROGRESS`. Set when `status` becomes\n  `COMPLETED`, `CANCELLED`, `EXPIRED`, or `LOST`.\n\n- **expiredAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for the\n  `IN_PROGRESS` window. `null` for unlimited bonuses (`validityInHours: 0` on the\n  rule). Computed as `activatedAt + rule.validityInHours × 3600 × 1000`.\n\n- **expiredOnClaimAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for\n  the `CLAIMED` activation window — i.e. when the player must call activate by.\n  `null` after the bonus has been activated. Computed as `createdAt +\n  timeForActivationInHours × 3600 × 1000`.\n\n- **isAutoActivates** (boolean, required) - Snapshot of the catalogue-side flag at\n  claim time. Drives whether the partner needs to call `activate-player-bonus`.\n\n- **bonusGiven** (object, optional) - Awarded **free-bet balance** in the player's\n  currency. `null` while `CLAIMED` (no money has been credited yet). Once the\n  bonus is `IN_PROGRESS`, this reflects the original awarded balance — it does\n  **not** decrement as the player places bets (use the bonus wallet balance API\n  to track real-time consumption).\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form (e.g.\n    `\"50000\"` = 500.00 TRY).\n  - **currency** (string, required) - Currency code, ISO 4217.\n\n- **totalWagering** (object, optional) - **Always `null` for `INTERNAL_FREE_BET`**\n  — free bets do not have a turnover requirement. Present only for player bonuses\n  created from non-free-bet catalogue entries that may surface via legacy paths.\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form.\n  - **currency** (string, required) - Currency code.\n\n- **currency** (string, required) - Currency the bonus was issued in. Matches the\n  player's currency at claim time. If the player later switches currency, the\n  existing player bonus retains its original `currency`.\n\n## Request Examples\n\n### Active player bonuses\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"CLAIMED\", \"IN_PROGRESS\"]\n}\n```\n\n### Terminal player bonuses (history view)\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"COMPLETED\", \"CANCELLED\", \"EXPIRED\", \"LOST\"]\n}\n```\n\n### Single-status query\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"IN_PROGRESS\"]\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Active free-bet player bonuses\n\n```json\n{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty list\n\n```json\n{\n    \"playerBonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `statuses` array is empty.\n- `statuses` contains a value that is not a known `PlayerBonusStatus`.\n- `externalUserId` is blank.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Slim shape.** Money fields are projected to plain `{amount, currency}` in the\n   player's currency — partners do not need the `MoneyTransaction` system / external\n   / currency-pair scaffolding the internal model carries.\n\n2. **Status filter is OR.** Multiple values in `statuses` produce a result containing\n   bonuses whose current status is **any** of the values.\n\n3. **Result ordering.** Result is sorted by `createdAt` descending (most recent\n   first). Partners that need a stable order should sort client-side on `id`.\n\n4. **Currency.** A player bonus is always denominated in a single currency, captured\n   at claim time. If the player later switches currency, existing player bonuses\n   retain their original `currency`.\n\n5. **`bonusGiven` does not decrement.** `bonusGiven` reflects the **original\n   awarded balance** — it does not track real-time consumption as the player places\n   bets. To observe live free-bet wallet balance, use the bonus-wallet APIs.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}"},{"id":"fcf0f2d2-e761-40f0-8283-749802fb9d81","name":"fail — invalid user","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"statuses\": [\n        \"CLAIMED\",\n        \"IN_PROGRESS\"\n    ]\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/find-player-bonuses","description":"# Endpoint for Finding Player Bonuses\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/find-player-bonuses`\n\n## Description\n\nThis endpoint returns the **internal sportsbook free-bet** player bonuses currently\nassociated with a given external player, filtered by status. Use it to determine\nwhether a player has any active or completed free-bet bonuses before deciding whether\nto offer a new claim, to drive a \"My Bonuses\" surface on the partner side, or to\nreconcile partner-side bookkeeping with Sumstats's record.\n\nThe response is **not paginated** — partners typically hold ≤ a few dozen player\nbonuses at a time per player.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats.\n\n- **statuses** (array of strings, required, length ≥ 1) - Status filter. The result\n  contains player bonuses whose current status is **any** of the values in this array\n  (OR semantics, equivalent to a SQL `IN` clause). Possible values:\n\n  - `CLAIMED` - Player bonus is created but not yet activated. Only reachable for\n    bonuses where `isAutoActivates: false` — the player has not yet received a\n    free-bet balance.\n  - `IN_PROGRESS` - Active player bonus. The player has a free-bet balance and is\n    placing bets towards completion.\n  - `WON` - Wagering bonus finished with a positive outcome and the player was\n    rewarded the win amount. Reachable for wagering-style bonuses (e.g. `CUSTOM`,\n    `FIRST_DEPOSIT`, `*_FREE_SPINS_WITH_WAGERING`) that may surface via legacy\n    paths. Pure `INTERNAL_FREE_BET` bonuses settle directly through the bet\n    engine and typically transition to `COMPLETED` / `LOST` instead.\n  - `COMPLETED` - The player exhausted the free-bet balance (or hit\n    `maxAmountOfBets`) and the bonus is finished.\n  - `CANCELLED` - Operator (or this integration) explicitly cancelled the player\n    bonus. `finishedAt` is set to the cancellation timestamp.\n  - `EXPIRED` - The bonus's claim window or activity window passed before the\n    player exhausted the balance. `expiredAt` / `expiredOnClaimAt` is set.\n  - `LOST` - All free-bet stakes settled as losses (and `maxAmountOfBets` was hit\n    or the validity expired with no winning stakes).\n\n  Empty array is rejected with `BAD_REQUEST`.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonuses** (array of objects, required) - List of player bonus objects\n  matching the status filter. Empty list when nothing matches.\n\n  Each player bonus object has the structure documented under **Player Bonus Fields**\n  below.\n\n### Player Bonus Fields\n\nThe slim partner-facing player-bonus shape. Internal fields dropped: `tinyId`,\n`playerId`, `snapshotVersion`, the heavy `bonusSnapshot` (replaced by `bonusId` +\n`bonusName` + `bonusType`), operator overrides (`overriddenBonusAmount`,\n`overriddenDepositAmount`, `overriddenFreeSpinsCount`, `overriddenWinAmount`,\n`wonGiven`), `heldDepositSum`, `wageringProductsProgress[]`,\n`freeBetProductsProgress[]`, and `updatedAt`.\n\nField-by-field semantics:\n\n- **id** (string, required) - Player-bonus identifier (UUID v7). **Store this for\n  reconciliation.** Distinct from `bonusId` — the `id` is unique per claim, while\n  `bonusId` is shared across all players who claimed the same catalogue bonus.\n\n- **bonusId** (string, required) - Underlying bonus id (UUID v7). Refers back to\n  the bonus catalogue entry returned by `find-available-bonuses`. Use this to fetch\n  the catalogue-side rules / criteria when needed.\n\n- **bonusName** (array of `{locale, translate}`, required) - Localised bonus names\n  captured at claim time. **Snapshot — does not reflect later catalogue edits.**\n  Partners should pick the entry matching the player's locale and fall back to\n  `en_US` when no exact match exists.\n\n- **bonusType** (enum, required) - Captured `bonusType` of the underlying bonus.\n  For this integration's contract, expect `INTERNAL_FREE_BET`. Other types may\n  surface if the player previously claimed via legacy paths.\n\n- **status** (enum, required) - Current player-bonus status. See the list of\n  possible values above in the request `statuses` field documentation.\n\n- **externalPlayerId** (string, optional) - Echo of the partner-side user id\n  supplied at claim. `null` for player bonuses created via internal flows (e.g.\n  legacy admin panel, VIP-club rewards).\n\n- **createdAt** (long, required) - Created-at timestamp (**epoch millis, UTC**)\n  when the player bonus was claimed.\n\n- **activatedAt** (long, optional) - Activated-at timestamp (epoch millis, UTC).\n  `null` while still `CLAIMED`. For auto-activating bonuses, equals `createdAt + Δ`\n  where Δ is small (the activation event is committed immediately after the claim\n  event).\n\n- **finishedAt** (long, optional) - Finished-at timestamp (epoch millis, UTC).\n  `null` while the bonus is `CLAIMED` or `IN_PROGRESS`. Set when `status` becomes\n  `COMPLETED`, `CANCELLED`, `EXPIRED`, or `LOST`.\n\n- **expiredAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for the\n  `IN_PROGRESS` window. `null` for unlimited bonuses (`validityInHours: 0` on the\n  rule). Computed as `activatedAt + rule.validityInHours × 3600 × 1000`.\n\n- **expiredOnClaimAt** (long, optional) - Expiry timestamp (epoch millis, UTC) for\n  the `CLAIMED` activation window — i.e. when the player must call activate by.\n  `null` after the bonus has been activated. Computed as `createdAt +\n  timeForActivationInHours × 3600 × 1000`.\n\n- **isAutoActivates** (boolean, required) - Snapshot of the catalogue-side flag at\n  claim time. Drives whether the partner needs to call `activate-player-bonus`.\n\n- **bonusGiven** (object, optional) - Awarded **free-bet balance** in the player's\n  currency. `null` while `CLAIMED` (no money has been credited yet). Once the\n  bonus is `IN_PROGRESS`, this reflects the original awarded balance — it does\n  **not** decrement as the player places bets (use the bonus wallet balance API\n  to track real-time consumption).\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form (e.g.\n    `\"50000\"` = 500.00 TRY).\n  - **currency** (string, required) - Currency code, ISO 4217.\n\n- **totalWagering** (object, optional) - **Always `null` for `INTERNAL_FREE_BET`**\n  — free bets do not have a turnover requirement. Present only for player bonuses\n  created from non-free-bet catalogue entries that may surface via legacy paths.\n\n  - **amount** (string, required) - Amount in raw integer minor-unit form.\n  - **currency** (string, required) - Currency code.\n\n- **currency** (string, required) - Currency the bonus was issued in. Matches the\n  player's currency at claim time. If the player later switches currency, the\n  existing player bonus retains its original `currency`.\n\n## Request Examples\n\n### Active player bonuses\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"CLAIMED\", \"IN_PROGRESS\"]\n}\n```\n\n### Terminal player bonuses (history view)\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"COMPLETED\", \"CANCELLED\", \"EXPIRED\", \"LOST\"]\n}\n```\n\n### Single-status query\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"statuses\": [\"IN_PROGRESS\"]\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Active free-bet player bonuses\n\n```json\n{\n    \"playerBonuses\": [\n        {\n            \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n            \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"500 TRY FREE BET\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": null,\n            \"expiredOnClaimAt\": 1762326005143,\n            \"isAutoActivates\": true,\n            \"bonusGiven\": {\n                \"amount\": \"50000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        },\n        {\n            \"id\": \"0192f888-aaaa-7e2f-bd44-deadbeef0001\",\n            \"bonusId\": \"0192bbb0-1234-7aef-9688-aabbccdd0011\",\n            \"bonusName\": [\n                {\n                    \"locale\": \"en_US\",\n                    \"translate\": \"Premier League Free Bet \\u2014 100 TRY\"\n                }\n            ],\n            \"bonusType\": \"INTERNAL_FREE_BET\",\n            \"status\": \"IN_PROGRESS\",\n            \"externalPlayerId\": \"ext_987654321\",\n            \"createdAt\": 1761721205143,\n            \"activatedAt\": 1761724805143,\n            \"finishedAt\": null,\n            \"expiredAt\": 1761983205143,\n            \"expiredOnClaimAt\": null,\n            \"isAutoActivates\": false,\n            \"bonusGiven\": {\n                \"amount\": \"10000\",\n                \"currency\": \"TRY\"\n            },\n            \"totalWagering\": null,\n            \"currency\": \"TRY\"\n        }\n    ]\n}\n```\n\n### Successful Response (200 OK) — Empty list\n\n```json\n{\n    \"playerBonuses\": []\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `statuses` array is empty.\n- `statuses` contains a value that is not a known `PlayerBonusStatus`.\n- `externalUserId` is blank.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'statuses' must contain at least one value\"\n}\n```\n\n### 400 Bad Request - Deserialization Error\n\n```json\n{\n    \"errorCode\": 4,\n    \"errorMessage\": \"Failed to deserialize request body\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Slim shape.** Money fields are projected to plain `{amount, currency}` in the\n   player's currency — partners do not need the `MoneyTransaction` system / external\n   / currency-pair scaffolding the internal model carries.\n\n2. **Status filter is OR.** Multiple values in `statuses` produce a result containing\n   bonuses whose current status is **any** of the values.\n\n3. **Result ordering.** Result is sorted by `createdAt` descending (most recent\n   first). Partners that need a stable order should sort client-side on `id`.\n\n4. **Currency.** A player bonus is always denominated in a single currency, captured\n   at claim time. If the player later switches currency, existing player bonuses\n   retain their original `currency`.\n\n5. **`bonusGiven` does not decrement.** `bonusGiven` reflects the **original\n   awarded balance** — it does not track real-time consumption as the player places\n   bets. To observe live free-bet wallet balance, use the bonus-wallet APIs.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}"}],"_postman_id":"e44ffde8-9b83-40a8-bfb8-63fe00dc6985"},{"name":"Claim Bonus for Player","id":"6bf615c6-0848-495a-9ae2-c3b277bba532","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"<h1 id=\"endpoint-for-claiming-a-bonus-on-behalf-of-a-player\">Endpoint for Claiming a Bonus on Behalf of a Player</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/bonus/claim-bonus-for-player</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint claims a specific <strong>internal sportsbook free-bet</strong> bonus on behalf of an\nexternal player. The exact effect depends on the bonus's <code>isAutoActivates</code> flag:</p>\n<ul>\n<li><strong><code>isAutoActivates: true</code></strong> - The freshly created player-bonus is also activated in\nthe same call. The response carries <code>status: \"IN_PROGRESS\"</code> plus a populated\n<code>activatedAt</code> and <code>bonusGiven</code> (the awarded free-bet balance).</li>\n<li><strong><code>isAutoActivates: false</code></strong> - The player-bonus is created with <code>status: \"CLAIMED\"</code>.\nThe partner must call <a href=\"#endpoint-for-activating-a-player-bonus\">Activate Player Bonus</a>\nwithin <code>timeForActivationInHours</code> hours to move the player-bonus to <code>IN_PROGRESS</code> —\notherwise it expires (<code>expiredOnClaimAt</code>).</li>\n</ul>\n<p>The action is recorded in the bonus action history as a <code>ClaimedByExternalSystem</code>\nentry — the same audit trail used by all partner-driven claims.</p>\n<p>If the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by Sumstats. Must match the\nbrand encoded in the HTTP Basic credentials.</p>\n</li>\n<li><p><strong>brand</strong> (string, optional) - Deprecated alias for <code>brandId</code>. Accepted during the\nbrand migration window only.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - External player id in the operator system.\nResolved automatically if unknown to Sumstats. Cannot be blank.</p>\n</li>\n<li><p><strong>bonusId</strong> (string, required) - UUID of the bonus to claim — typically taken from\na prior Find Available Bonuses response. Must reference an enabled, in-activity-window\nfree-bet bonus that supports the player's currency. Cannot be blank.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>playerBonus</strong> (object, required) - The freshly-created player bonus. Same slim\nshape returned by Find Player Bonuses, Activate, and Cancel — see the\n<a href=\"#endpoint-for-finding-player-bonuses\">Find Player Bonuses</a> field reference for the\nfield-by-field description. Notable fields after a successful claim:</p>\n<ul>\n<li><strong>id</strong> (string, required) - Player-bonus identifier (UUID v7).\n<strong>Store this for reconciliation.</strong></li>\n<li><strong>bonusId</strong> (string, required) - Echo of the request <code>bonusId</code>.</li>\n<li><strong>status</strong> (enum, required) - <code>\"CLAIMED\"</code> if the catalogue bonus has\n<code>isAutoActivates: false</code>, otherwise <code>\"IN_PROGRESS\"</code>.</li>\n<li><strong>createdAt</strong> (long, required) - Claim timestamp (epoch millis, UTC).</li>\n<li><strong>activatedAt</strong> (long, optional) - Populated only when the bonus auto-activated.</li>\n<li><strong>bonusGiven</strong> (object, optional) - Populated when the bonus auto-activated:\nthe awarded free-bet balance in the player's currency. <code>null</code> for <code>CLAIMED</code>.</li>\n<li><strong>expiredOnClaimAt</strong> (long, optional) - Activation deadline for <code>CLAIMED</code>\nstatus. <code>null</code> after auto-activation.</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"request-example\">Request Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n</code></pre>\n<h2 id=\"response-examples\">Response Examples</h2>\n<h3 id=\"successful-response-200-ok--auto-activated-free-bet\">Successful Response (200 OK) — Auto-activated free bet</h3>\n<p>When the underlying free-bet bonus has <code>isAutoActivates: true</code>, the player-bonus is\ncreated and activated in the same call. Note <code>status: \"IN_PROGRESS\"</code>, populated\n<code>activatedAt</code>, and populated <code>bonusGiven</code> (the awarded free-bet balance).</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n</code></pre>\n<h3 id=\"successful-response-200-ok--manual-claim-free-bet-claimed\">Successful Response (200 OK) — Manual-claim free bet (CLAIMED)</h3>\n<p>When the underlying free-bet bonus has <code>isAutoActivates: false</code>, the player-bonus\nstops at <code>CLAIMED</code>. Note <code>activatedAt: null</code>, <code>bonusGiven: null</code>, and a populated\n<code>expiredOnClaimAt</code> — the partner must call activate before that timestamp.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<p>Occurs when request validation fails. Common causes:</p>\n<ul>\n<li><code>bonusId</code> is blank or not a valid UUID.</li>\n<li><code>externalUserId</code> is blank.</li>\n<li>Missing <code>brandId</code>.</li>\n</ul>\n<p><strong>Example Error Response:</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<p>Maps to the legacy <code>player_cannot_be_resolved</code> domain code. Occurs when the\n<code>externalUserId</code> cannot be resolved automatically.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-not-found\">400 Bad Request - Bonus Not Found</h3>\n<p>Maps to the legacy <code>bonus.not_found</code> domain code. Occurs when no bonus exists with\nthe given <code>bonusId</code> (or the bonus has been deleted).</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-disabled\">400 Bad Request - Bonus Disabled</h3>\n<p>Maps to the legacy <code>bonus.disabled</code> domain code. Occurs when the bonus exists but\nthe operator has switched it off (<code>enabled: false</code>).</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-not-available\">400 Bad Request - Bonus Not Available</h3>\n<p>Maps to the legacy <code>bonus.not_available</code> domain code. Occurs when the bonus's\n<code>activityTime</code> window has expired or has not started yet.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-user-limits-exceeded\">400 Bad Request - Bonus User Limits Exceeded</h3>\n<p>Maps to the legacy <code>bonus.user_limits_exceeded</code> domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-total-limits-exceeded\">400 Bad Request - Bonus Total Limits Exceeded</h3>\n<p>Maps to the legacy <code>bonus.total_limits_exceeded</code> domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-eligibility-claim-rules-not-satisfied\">400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied</h3>\n<p>Maps to the legacy <code>bonus.eligibility_claim_rules_not_satisfied</code> domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---player-bonus-already-claimed\">400 Bad Request - Player Bonus Already Claimed</h3>\n<p>Maps to the legacy <code>player_bonus.player_has_already_claimed_this_bonus</code> domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically <code>CLAIMED</code> or <code>IN_PROGRESS</code>, sometimes also\n<code>COMPLETED</code> for one-off bonuses).</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-one-per-player-tag-violation\">400 Bad Request - Bonus One-Per-Player Tag Violation</h3>\n<p>Maps to the legacy <code>bonus_tag_validation.already_used_with_one_per_player_tag</code>\ndomain code. Occurs when the bonus has the <code>One Per Player</code> tag and the player has\npreviously claimed any bonus carrying the same tag.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-new-customer-tag-violation\">400 Bad Request - Bonus New-Customer Tag Violation</h3>\n<p>Maps to the legacy <code>bonus_tag_validation.already_used_bonus_with_new_customer_tag</code>\ndomain code. Occurs when the bonus has the <code>New Customer</code> tag and the player has\npreviously claimed any bonus carrying the same tag.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n</code></pre>\n<h3 id=\"401-unauthorized---invalid-credentials\">401 Unauthorized - Invalid Credentials</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>Idempotency.</strong> The endpoint is <strong>not</strong> idempotent. A second <code>claim-bonus-for-player</code>\ncall for the same <code>(externalUserId, bonusId)</code> pair returns\n<code>PLAYER_BONUS_ALREADY_CLAIMED</code> (307), not the previously-created <code>playerBonus</code>.\nUse Find Player Bonuses to fetch the existing player bonus when you need a\nre-read.</p>\n</li>\n<li><p><strong>Player registration side-effect.</strong> When <code>externalUserId</code> is unknown to Sumstats,\nthe system attempts to register the player automatically before evaluating\neligibility. If automatic registration fails, the request fails with\n<code>INVALID_USER</code> (109).</p>\n</li>\n<li><p><strong>Bonus snapshot.</strong> The newly-created player bonus captures a snapshot of the\ncatalogue bonus (<code>bonusSnapshot.id</code>, <code>bonusSnapshot.name</code>,\n<code>bonusSnapshot.bonusType</code>) at claim time. Subsequent edits to the catalogue bonus\ndo <strong>not</strong> mutate existing player bonuses — partners always see the snapshot the\nplayer was awarded.</p>\n</li>\n<li><p><strong>Action-history entry.</strong> The claim is recorded in the bonus action history as a\n<code>ClaimedByExternalSystem</code> entry (<code>actionType: CLAIMED_BY_EXTERNAL_SYSTEM</code>), with\nthe external request id captured for audit. The same entry is used by all\npartner-side claims regardless of bonus type.</p>\n</li>\n<li><p><strong>Currency selection.</strong> The player bonus is denominated in the player's currency\nat claim time. The bonus must support the player's currency (<code>bonus.currencies</code>\ncontains the player currency); otherwise the bonus engine rejects the claim with\n<code>BONUS_NOT_AVAILABLE</code> (303).</p>\n</li>\n<li><p><strong>Bonus tags affect availability.</strong> <code>One Per Player</code> and <code>New Customer</code> tags are\nevaluated together with the catalogue eligibility rules. A bonus with\n<code>New Customer</code> tag is unclaimable for any player who has previously claimed any\n<code>New-Customer</code>-tagged bonus regardless of which one.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Basic base64(username:password)\nContent-Type: application/json\n</code></pre>\n<p>Use the <code>brandId</code> body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request <code>brandId</code> matches.</p>\n","urlObject":{"path":["external-casino-client","v1","bonus","claim-bonus-for-player"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"df669f33-a45d-4e2b-96e3-bdbc9512adcc","name":"success — Auto-activated free bet","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}"},{"id":"08f5c137-9c3c-45bb-960a-e42b6cbfdd57","name":"success — Manual-claim free bet (CLAIMED)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}"},{"id":"6de5efb1-350c-41de-837a-1dfdc5f32864","name":"fail — already claimed (307)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}"},{"id":"af94ff8f-4a21-4574-8b4a-9c83473b5a94","name":"fail — bonus not found (301)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}"},{"id":"175b9e33-3ee9-4c23-a0b8-27f18ffce6d4","name":"fail — eligibility rules (306)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}"},{"id":"18701320-e449-4059-8e1e-bb6f3aeda704","name":"fail — new-customer tag (309)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/claim-bonus-for-player","description":"# Endpoint for Claiming a Bonus on Behalf of a Player\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/claim-bonus-for-player`\n\n## Description\n\nThis endpoint claims a specific **internal sportsbook free-bet** bonus on behalf of an\nexternal player. The exact effect depends on the bonus's `isAutoActivates` flag:\n\n- **`isAutoActivates: true`** - The freshly created player-bonus is also activated in\n  the same call. The response carries `status: \"IN_PROGRESS\"` plus a populated\n  `activatedAt` and `bonusGiven` (the awarded free-bet balance).\n- **`isAutoActivates: false`** - The player-bonus is created with `status: \"CLAIMED\"`.\n  The partner must call [Activate Player Bonus](#endpoint-for-activating-a-player-bonus)\n  within `timeForActivationInHours` hours to move the player-bonus to `IN_PROGRESS` —\n  otherwise it expires (`expiredOnClaimAt`).\n\nThe action is recorded in the bonus action history as a `ClaimedByExternalSystem`\nentry — the same audit trail used by all partner-driven claims.\n\nIf the bonus is not available for this player (limit exceeded, claim rules not\nsatisfied, already-claimed, tag conflict, etc.) the call is rejected with one of the\ndomain-mapped error codes documented below.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Resolved automatically if unknown to Sumstats. Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus to claim — typically taken from\n  a prior Find Available Bonuses response. Must reference an enabled, in-activity-window\n  free-bet bonus that supports the player's currency. Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The freshly-created player bonus. Same slim\n  shape returned by Find Player Bonuses, Activate, and Cancel — see the\n  [Find Player Bonuses](#endpoint-for-finding-player-bonuses) field reference for the\n  field-by-field description. Notable fields after a successful claim:\n\n  - **id** (string, required) - Player-bonus identifier (UUID v7).\n    **Store this for reconciliation.**\n  - **bonusId** (string, required) - Echo of the request `bonusId`.\n  - **status** (enum, required) - `\"CLAIMED\"` if the catalogue bonus has\n    `isAutoActivates: false`, otherwise `\"IN_PROGRESS\"`.\n  - **createdAt** (long, required) - Claim timestamp (epoch millis, UTC).\n  - **activatedAt** (long, optional) - Populated only when the bonus auto-activated.\n  - **bonusGiven** (object, optional) - Populated when the bonus auto-activated:\n    the awarded free-bet balance in the player's currency. `null` for `CLAIMED`.\n  - **expiredOnClaimAt** (long, optional) - Activation deadline for `CLAIMED`\n    status. `null` after auto-activation.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Auto-activated free bet\n\nWhen the underlying free-bet bonus has `isAutoActivates: true`, the player-bonus is\ncreated and activated in the same call. Note `status: \"IN_PROGRESS\"`, populated\n`activatedAt`, and populated `bonusGiven` (the awarded free-bet balance).\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Manual-claim free bet (CLAIMED)\n\nWhen the underlying free-bet bonus has `isAutoActivates: false`, the player-bonus\nstops at `CLAIMED`. Note `activatedAt: null`, `bonusGiven: null`, and a populated\n`expiredOnClaimAt` — the partner must call activate before that timestamp.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CLAIMED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\nOccurs when request validation fails. Common causes:\n\n- `bonusId` is blank or not a valid UUID.\n- `externalUserId` is blank.\n- Missing `brandId`.\n\n**Example Error Response:**\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\nMaps to the legacy `player_cannot_be_resolved` domain code. Occurs when the\n`externalUserId` cannot be resolved automatically.\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Bonus Not Found\n\nMaps to the legacy `bonus.not_found` domain code. Occurs when no bonus exists with\nthe given `bonusId` (or the bonus has been deleted).\n\n```json\n{\n    \"errorCode\": 301,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' not found\"\n}\n```\n\n### 400 Bad Request - Bonus Disabled\n\nMaps to the legacy `bonus.disabled` domain code. Occurs when the bonus exists but\nthe operator has switched it off (`enabled: false`).\n\n```json\n{\n    \"errorCode\": 302,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is disabled\"\n}\n```\n\n### 400 Bad Request - Bonus Not Available\n\nMaps to the legacy `bonus.not_available` domain code. Occurs when the bonus's\n`activityTime` window has expired or has not started yet.\n\n```json\n{\n    \"errorCode\": 303,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' is not available, activity time has expired\"\n}\n```\n\n### 400 Bad Request - Bonus User Limits Exceeded\n\nMaps to the legacy `bonus.user_limits_exceeded` domain code. Occurs when the\nplayer-scoped daily / weekly / total claim limit on the bonus would be exceeded.\n\n```json\n{\n    \"errorCode\": 304,\n    \"errorMessage\": \"User limits exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Total Limits Exceeded\n\nMaps to the legacy `bonus.total_limits_exceeded` domain code. Occurs when the\noperator-wide total claim limit on the bonus has been hit.\n\n```json\n{\n    \"errorCode\": 305,\n    \"errorMessage\": \"Total bonus claim limit exceeded for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Claim Rules Not Satisfied\n\nMaps to the legacy `bonus.eligibility_claim_rules_not_satisfied` domain code. Occurs\nwhen the bonus has claim rules (deposit thresholds, country gating, age gating,\nprevious-bonus-completion gating, etc.) and the player does not satisfy at least one\nof them.\n\n```json\n{\n    \"errorCode\": 306,\n    \"errorMessage\": \"Eligibility claim rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Claimed\n\nMaps to the legacy `player_bonus.player_has_already_claimed_this_bonus` domain code.\nOccurs when the player has an existing player-bonus for this bonus that is in a\nstatus preventing re-claim (typically `CLAIMED` or `IN_PROGRESS`, sometimes also\n`COMPLETED` for one-off bonuses).\n\n```json\n{\n    \"errorCode\": 307,\n    \"errorMessage\": \"Bonus with id '0192f721-29ae-7aef-9688-7c8bc5508b88' has already been claimed by this player\"\n}\n```\n\n### 400 Bad Request - Bonus One-Per-Player Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_with_one_per_player_tag`\ndomain code. Occurs when the bonus has the `One Per Player` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 308,\n    \"errorMessage\": \"Bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' was already used by player with the 'One Per Player' tag\"\n}\n```\n\n### 400 Bad Request - Bonus New-Customer Tag Violation\n\nMaps to the legacy `bonus_tag_validation.already_used_bonus_with_new_customer_tag`\ndomain code. Occurs when the bonus has the `New Customer` tag and the player has\npreviously claimed any bonus carrying the same tag.\n\n```json\n{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag — bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **Idempotency.** The endpoint is **not** idempotent. A second `claim-bonus-for-player`\n   call for the same `(externalUserId, bonusId)` pair returns\n   `PLAYER_BONUS_ALREADY_CLAIMED` (307), not the previously-created `playerBonus`.\n   Use Find Player Bonuses to fetch the existing player bonus when you need a\n   re-read.\n\n2. **Player registration side-effect.** When `externalUserId` is unknown to Sumstats,\n   the system attempts to register the player automatically before evaluating\n   eligibility. If automatic registration fails, the request fails with\n   `INVALID_USER` (109).\n\n3. **Bonus snapshot.** The newly-created player bonus captures a snapshot of the\n   catalogue bonus (`bonusSnapshot.id`, `bonusSnapshot.name`,\n   `bonusSnapshot.bonusType`) at claim time. Subsequent edits to the catalogue bonus\n   do **not** mutate existing player bonuses — partners always see the snapshot the\n   player was awarded.\n\n4. **Action-history entry.** The claim is recorded in the bonus action history as a\n   `ClaimedByExternalSystem` entry (`actionType: CLAIMED_BY_EXTERNAL_SYSTEM`), with\n   the external request id captured for audit. The same entry is used by all\n   partner-side claims regardless of bonus type.\n\n5. **Currency selection.** The player bonus is denominated in the player's currency\n   at claim time. The bonus must support the player's currency (`bonus.currencies`\n   contains the player currency); otherwise the bonus engine rejects the claim with\n   `BONUS_NOT_AVAILABLE` (303).\n\n6. **Bonus tags affect availability.** `One Per Player` and `New Customer` tags are\n   evaluated together with the catalogue eligibility rules. A bonus with\n   `New Customer` tag is unclaimable for any player who has previously claimed any\n   `New-Customer`-tagged bonus regardless of which one.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 309,\n    \"errorMessage\": \"Player has already claimed bonuses with the 'New Customer' tag \\u2014 bonus '0192f721-29ae-7aef-9688-7c8bc5508b88' cannot be claimed\"\n}"}],"_postman_id":"6bf615c6-0848-495a-9ae2-c3b277bba532"},{"name":"Activate Player Bonus","id":"8f24f67f-e4e9-4b9c-9d48-41ee2da4a6fc","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/activate-player-bonus","description":"<h1 id=\"endpoint-for-activating-a-player-bonus\">Endpoint for Activating a Player Bonus</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/bonus/activate-player-bonus</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint moves a previously claimed <strong>internal sportsbook free-bet</strong> player\nbonus from <code>CLAIMED</code> to <code>IN_PROGRESS</code> so the player can start placing bets against\nthe free-bet balance. Use it when your side has decided to activate a bonus that was\nclaimed but not yet auto-activated (the bonus was claimed with\n<code>isAutoActivates: false</code> on its catalogue entry).</p>\n<p>The activation is recorded in the bonus action history as an\n<code>ActivatedBySystemDetails</code> entry (<code>actionType: ACTIVATED_BY_SYSTEM</code>) — the same\n<code>SYSTEM</code> initiator used by Sumstats's internal auto-activation logic. The player\nbonus's <code>activatedAt</code> is set to the activation timestamp; <code>bonusGiven</code> is populated\nwith the awarded free-bet balance in the player's currency.</p>\n<p>For bonuses where <code>isAutoActivates: true</code> activation already happened on claim —\ncalling this endpoint for such a player bonus returns\n<code>PLAYER_BONUS_ALREADY_ACTIVATED</code> (312).</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by Sumstats. Must match the\nbrand encoded in the HTTP Basic credentials.</p>\n</li>\n<li><p><strong>brand</strong> (string, optional) - Deprecated alias for <code>brandId</code>. Accepted during the\nbrand migration window only.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - External player id in the operator system.\nCannot be blank.</p>\n</li>\n<li><p><strong>bonusId</strong> (string, required) - UUID of the bonus whose <code>CLAIMED</code> player-bonus\nshould be activated. Must match an existing <code>CLAIMED</code> player-bonus for the player —\ni.e. the player must have previously called <code>claim-bonus-for-player</code> for the same\nbonus and not yet activated.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>playerBonus</strong> (object, required) - The activated player bonus. Same slim shape\ndocumented under <a href=\"#endpoint-for-finding-player-bonuses\">Find Player Bonuses</a>.\nNotable fields after a successful activation:</p>\n<ul>\n<li><strong>status</strong> (enum, required) - <code>\"IN_PROGRESS\"</code>.</li>\n<li><strong>activatedAt</strong> (long, required) - Activation timestamp (epoch millis, UTC).</li>\n<li><strong>bonusGiven</strong> (object, required) - Awarded free-bet balance in the player's\ncurrency.</li>\n<li><strong>expiredAt</strong> (long, optional) - Set if the free-bet rule has a finite validity\n(<code>bonusSize.rule.validityInHours</code> &gt; 0). Computed as <code>activatedAt + validityInHours × 3600 × 1000</code>.</li>\n<li><strong>expiredOnClaimAt</strong> (long, optional) - Cleared on activation — <code>null</code> after\nthe bonus has been activated.</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"request-example\">Request Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n</code></pre>\n<h2 id=\"response-example\">Response Example</h2>\n<h3 id=\"successful-response-200-ok\">Successful Response (200 OK)</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---player-bonus-not-found\">400 Bad Request - Player Bonus Not Found</h3>\n<p>Occurs when no <code>CLAIMED</code> player bonus matches the (<code>externalUserId</code>, <code>bonusId</code>)\npair. Common causes:</p>\n<ul>\n<li>The player never claimed this bonus.</li>\n<li>The previously-claimed player bonus was already activated, cancelled, or expired.</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---player-bonus-already-activated\">400 Bad Request - Player Bonus Already Activated</h3>\n<p>Maps to the legacy <code>player_bonus.already_activated</code> domain code. Occurs when the\nplayer bonus is already <code>IN_PROGRESS</code> (or terminal — <code>COMPLETED</code>, <code>CANCELLED</code>,\n<code>EXPIRED</code>, <code>LOST</code>).</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---bonus-eligibility-activate-rules-not-satisfied\">400 Bad Request - Bonus Eligibility Activate Rules Not Satisfied</h3>\n<p>Maps to the legacy <code>bonus.activate_rules_not_completely_satisfied</code> domain code.\nOccurs when the bonus has activate-time rules (e.g. required deposits, identity\nverification) that are not yet satisfied at activation time.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"401-unauthorized---invalid-credentials\">401 Unauthorized - Invalid Credentials</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>No-op for auto-activating bonuses.</strong> When the underlying bonus has\n<code>isAutoActivates: true</code>, calling activate after a successful claim returns\n<code>PLAYER_BONUS_ALREADY_ACTIVATED</code> (312). Partners can skip the activate step\nentirely for these bonuses — branch on the catalogue-side <code>isAutoActivates</code> flag.</p>\n</li>\n<li><p><strong>Activation initiator.</strong> The action is recorded with <code>ActivatePlayerBonusInitiator = SYSTEM</code>, matching the value used by Sumstats's internal auto-activation logic.\nThis is intentional — the partner integration is treated as a system actor, not\nas an operator user.</p>\n</li>\n<li><p><strong>Activate-time rules.</strong> A free-bet bonus may have separate activate-time rules\n(<code>eligibility.activateRules</code>) on top of claim-time rules. For example, a bonus\nmay be claimable on registration but require a qualifying deposit before it can\nbe activated. The <code>BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED</code> (313) error\nsurfaces this case.</p>\n</li>\n<li><p><strong>Activation deadline.</strong> If the bonus is <code>CLAIMED</code> past its <code>expiredOnClaimAt</code>\ntimestamp, activation fails with <code>PLAYER_BONUS_NOT_FOUND</code> (310) because the\nengine transitions the player bonus to <code>EXPIRED</code> automatically.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Basic base64(username:password)\nContent-Type: application/json\n</code></pre>\n<p>Use the <code>brandId</code> body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request <code>brandId</code> matches.</p>\n","urlObject":{"path":["external-casino-client","v1","bonus","activate-player-bonus"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"07bf4e9a-e34e-4c1a-a3d9-2918d04b8f75","name":"success","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/activate-player-bonus","description":"# Endpoint for Activating a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/activate-player-bonus`\n\n## Description\n\nThis endpoint moves a previously claimed **internal sportsbook free-bet** player\nbonus from `CLAIMED` to `IN_PROGRESS` so the player can start placing bets against\nthe free-bet balance. Use it when your side has decided to activate a bonus that was\nclaimed but not yet auto-activated (the bonus was claimed with\n`isAutoActivates: false` on its catalogue entry).\n\nThe activation is recorded in the bonus action history as an\n`ActivatedBySystemDetails` entry (`actionType: ACTIVATED_BY_SYSTEM`) — the same\n`SYSTEM` initiator used by Sumstats's internal auto-activation logic. The player\nbonus's `activatedAt` is set to the activation timestamp; `bonusGiven` is populated\nwith the awarded free-bet balance in the player's currency.\n\nFor bonuses where `isAutoActivates: true` activation already happened on claim —\ncalling this endpoint for such a player bonus returns\n`PLAYER_BONUS_ALREADY_ACTIVATED` (312).\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose `CLAIMED` player-bonus\n  should be activated. Must match an existing `CLAIMED` player-bonus for the player —\n  i.e. the player must have previously called `claim-bonus-for-player` for the same\n  bonus and not yet activated.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The activated player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful activation:\n\n  - **status** (enum, required) - `\"IN_PROGRESS\"`.\n  - **activatedAt** (long, required) - Activation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, required) - Awarded free-bet balance in the player's\n    currency.\n  - **expiredAt** (long, optional) - Set if the free-bet rule has a finite validity\n    (`bonusSize.rule.validityInHours` > 0). Computed as `activatedAt +\n    validityInHours × 3600 × 1000`.\n  - **expiredOnClaimAt** (long, optional) - Cleared on activation — `null` after\n    the bonus has been activated.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Example\n\n### Successful Response (200 OK)\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no `CLAIMED` player bonus matches the (`externalUserId`, `bonusId`)\npair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus was already activated, cancelled, or expired.\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Activated\n\nMaps to the legacy `player_bonus.already_activated` domain code. Occurs when the\nplayer bonus is already `IN_PROGRESS` (or terminal — `COMPLETED`, `CANCELLED`,\n`EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Activate Rules Not Satisfied\n\nMaps to the legacy `bonus.activate_rules_not_completely_satisfied` domain code.\nOccurs when the bonus has activate-time rules (e.g. required deposits, identity\nverification) that are not yet satisfied at activation time.\n\n```json\n{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **No-op for auto-activating bonuses.** When the underlying bonus has\n   `isAutoActivates: true`, calling activate after a successful claim returns\n   `PLAYER_BONUS_ALREADY_ACTIVATED` (312). Partners can skip the activate step\n   entirely for these bonuses — branch on the catalogue-side `isAutoActivates` flag.\n\n2. **Activation initiator.** The action is recorded with `ActivatePlayerBonusInitiator\n   = SYSTEM`, matching the value used by Sumstats's internal auto-activation logic.\n   This is intentional — the partner integration is treated as a system actor, not\n   as an operator user.\n\n3. **Activate-time rules.** A free-bet bonus may have separate activate-time rules\n   (`eligibility.activateRules`) on top of claim-time rules. For example, a bonus\n   may be claimable on registration but require a qualifying deposit before it can\n   be activated. The `BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED` (313) error\n   surfaces this case.\n\n4. **Activation deadline.** If the bonus is `CLAIMED` past its `expiredOnClaimAt`\n   timestamp, activation fails with `PLAYER_BONUS_NOT_FOUND` (310) because the\n   engine transitions the player bonus to `EXPIRED` automatically.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}"},{"id":"2bbb5a8e-cb34-4816-87c3-01c529b4c2c2","name":"fail — already activated (312)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/activate-player-bonus","description":"# Endpoint for Activating a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/activate-player-bonus`\n\n## Description\n\nThis endpoint moves a previously claimed **internal sportsbook free-bet** player\nbonus from `CLAIMED` to `IN_PROGRESS` so the player can start placing bets against\nthe free-bet balance. Use it when your side has decided to activate a bonus that was\nclaimed but not yet auto-activated (the bonus was claimed with\n`isAutoActivates: false` on its catalogue entry).\n\nThe activation is recorded in the bonus action history as an\n`ActivatedBySystemDetails` entry (`actionType: ACTIVATED_BY_SYSTEM`) — the same\n`SYSTEM` initiator used by Sumstats's internal auto-activation logic. The player\nbonus's `activatedAt` is set to the activation timestamp; `bonusGiven` is populated\nwith the awarded free-bet balance in the player's currency.\n\nFor bonuses where `isAutoActivates: true` activation already happened on claim —\ncalling this endpoint for such a player bonus returns\n`PLAYER_BONUS_ALREADY_ACTIVATED` (312).\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose `CLAIMED` player-bonus\n  should be activated. Must match an existing `CLAIMED` player-bonus for the player —\n  i.e. the player must have previously called `claim-bonus-for-player` for the same\n  bonus and not yet activated.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The activated player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful activation:\n\n  - **status** (enum, required) - `\"IN_PROGRESS\"`.\n  - **activatedAt** (long, required) - Activation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, required) - Awarded free-bet balance in the player's\n    currency.\n  - **expiredAt** (long, optional) - Set if the free-bet rule has a finite validity\n    (`bonusSize.rule.validityInHours` > 0). Computed as `activatedAt +\n    validityInHours × 3600 × 1000`.\n  - **expiredOnClaimAt** (long, optional) - Cleared on activation — `null` after\n    the bonus has been activated.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Example\n\n### Successful Response (200 OK)\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no `CLAIMED` player bonus matches the (`externalUserId`, `bonusId`)\npair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus was already activated, cancelled, or expired.\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Activated\n\nMaps to the legacy `player_bonus.already_activated` domain code. Occurs when the\nplayer bonus is already `IN_PROGRESS` (or terminal — `COMPLETED`, `CANCELLED`,\n`EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Activate Rules Not Satisfied\n\nMaps to the legacy `bonus.activate_rules_not_completely_satisfied` domain code.\nOccurs when the bonus has activate-time rules (e.g. required deposits, identity\nverification) that are not yet satisfied at activation time.\n\n```json\n{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **No-op for auto-activating bonuses.** When the underlying bonus has\n   `isAutoActivates: true`, calling activate after a successful claim returns\n   `PLAYER_BONUS_ALREADY_ACTIVATED` (312). Partners can skip the activate step\n   entirely for these bonuses — branch on the catalogue-side `isAutoActivates` flag.\n\n2. **Activation initiator.** The action is recorded with `ActivatePlayerBonusInitiator\n   = SYSTEM`, matching the value used by Sumstats's internal auto-activation logic.\n   This is intentional — the partner integration is treated as a system actor, not\n   as an operator user.\n\n3. **Activate-time rules.** A free-bet bonus may have separate activate-time rules\n   (`eligibility.activateRules`) on top of claim-time rules. For example, a bonus\n   may be claimable on registration but require a qualifying deposit before it can\n   be activated. The `BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED` (313) error\n   surfaces this case.\n\n4. **Activation deadline.** If the bonus is `CLAIMED` past its `expiredOnClaimAt`\n   timestamp, activation fails with `PLAYER_BONUS_NOT_FOUND` (310) because the\n   engine transitions the player bonus to `EXPIRED` automatically.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}"},{"id":"a9131992-b854-48e2-9c63-39a096063b3d","name":"fail — activate rules (313)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/activate-player-bonus","description":"# Endpoint for Activating a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/activate-player-bonus`\n\n## Description\n\nThis endpoint moves a previously claimed **internal sportsbook free-bet** player\nbonus from `CLAIMED` to `IN_PROGRESS` so the player can start placing bets against\nthe free-bet balance. Use it when your side has decided to activate a bonus that was\nclaimed but not yet auto-activated (the bonus was claimed with\n`isAutoActivates: false` on its catalogue entry).\n\nThe activation is recorded in the bonus action history as an\n`ActivatedBySystemDetails` entry (`actionType: ACTIVATED_BY_SYSTEM`) — the same\n`SYSTEM` initiator used by Sumstats's internal auto-activation logic. The player\nbonus's `activatedAt` is set to the activation timestamp; `bonusGiven` is populated\nwith the awarded free-bet balance in the player's currency.\n\nFor bonuses where `isAutoActivates: true` activation already happened on claim —\ncalling this endpoint for such a player bonus returns\n`PLAYER_BONUS_ALREADY_ACTIVATED` (312).\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose `CLAIMED` player-bonus\n  should be activated. Must match an existing `CLAIMED` player-bonus for the player —\n  i.e. the player must have previously called `claim-bonus-for-player` for the same\n  bonus and not yet activated.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The activated player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful activation:\n\n  - **status** (enum, required) - `\"IN_PROGRESS\"`.\n  - **activatedAt** (long, required) - Activation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, required) - Awarded free-bet balance in the player's\n    currency.\n  - **expiredAt** (long, optional) - Set if the free-bet rule has a finite validity\n    (`bonusSize.rule.validityInHours` > 0). Computed as `activatedAt +\n    validityInHours × 3600 × 1000`.\n  - **expiredOnClaimAt** (long, optional) - Cleared on activation — `null` after\n    the bonus has been activated.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Example\n\n### Successful Response (200 OK)\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no `CLAIMED` player bonus matches the (`externalUserId`, `bonusId`)\npair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus was already activated, cancelled, or expired.\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Activated\n\nMaps to the legacy `player_bonus.already_activated` domain code. Occurs when the\nplayer bonus is already `IN_PROGRESS` (or terminal — `COMPLETED`, `CANCELLED`,\n`EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Activate Rules Not Satisfied\n\nMaps to the legacy `bonus.activate_rules_not_completely_satisfied` domain code.\nOccurs when the bonus has activate-time rules (e.g. required deposits, identity\nverification) that are not yet satisfied at activation time.\n\n```json\n{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **No-op for auto-activating bonuses.** When the underlying bonus has\n   `isAutoActivates: true`, calling activate after a successful claim returns\n   `PLAYER_BONUS_ALREADY_ACTIVATED` (312). Partners can skip the activate step\n   entirely for these bonuses — branch on the catalogue-side `isAutoActivates` flag.\n\n2. **Activation initiator.** The action is recorded with `ActivatePlayerBonusInitiator\n   = SYSTEM`, matching the value used by Sumstats's internal auto-activation logic.\n   This is intentional — the partner integration is treated as a system actor, not\n   as an operator user.\n\n3. **Activate-time rules.** A free-bet bonus may have separate activate-time rules\n   (`eligibility.activateRules`) on top of claim-time rules. For example, a bonus\n   may be claimable on registration but require a qualifying deposit before it can\n   be activated. The `BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED` (313) error\n   surfaces this case.\n\n4. **Activation deadline.** If the bonus is `CLAIMED` past its `expiredOnClaimAt`\n   timestamp, activation fails with `PLAYER_BONUS_NOT_FOUND` (310) because the\n   engine transitions the player bonus to `EXPIRED` automatically.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}"},{"id":"0f6c2f65-12c4-44b8-9d76-ce397f059edc","name":"fail — player bonus not found (310)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/activate-player-bonus","description":"# Endpoint for Activating a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/activate-player-bonus`\n\n## Description\n\nThis endpoint moves a previously claimed **internal sportsbook free-bet** player\nbonus from `CLAIMED` to `IN_PROGRESS` so the player can start placing bets against\nthe free-bet balance. Use it when your side has decided to activate a bonus that was\nclaimed but not yet auto-activated (the bonus was claimed with\n`isAutoActivates: false` on its catalogue entry).\n\nThe activation is recorded in the bonus action history as an\n`ActivatedBySystemDetails` entry (`actionType: ACTIVATED_BY_SYSTEM`) — the same\n`SYSTEM` initiator used by Sumstats's internal auto-activation logic. The player\nbonus's `activatedAt` is set to the activation timestamp; `bonusGiven` is populated\nwith the awarded free-bet balance in the player's currency.\n\nFor bonuses where `isAutoActivates: true` activation already happened on claim —\ncalling this endpoint for such a player bonus returns\n`PLAYER_BONUS_ALREADY_ACTIVATED` (312).\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose `CLAIMED` player-bonus\n  should be activated. Must match an existing `CLAIMED` player-bonus for the player —\n  i.e. the player must have previously called `claim-bonus-for-player` for the same\n  bonus and not yet activated.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The activated player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful activation:\n\n  - **status** (enum, required) - `\"IN_PROGRESS\"`.\n  - **activatedAt** (long, required) - Activation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, required) - Awarded free-bet balance in the player's\n    currency.\n  - **expiredAt** (long, optional) - Set if the free-bet rule has a finite validity\n    (`bonusSize.rule.validityInHours` > 0). Computed as `activatedAt +\n    validityInHours × 3600 × 1000`.\n  - **expiredOnClaimAt** (long, optional) - Cleared on activation — `null` after\n    the bonus has been activated.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Example\n\n### Successful Response (200 OK)\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"IN_PROGRESS\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": null,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no `CLAIMED` player bonus matches the (`externalUserId`, `bonusId`)\npair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus was already activated, cancelled, or expired.\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Already Activated\n\nMaps to the legacy `player_bonus.already_activated` domain code. Occurs when the\nplayer bonus is already `IN_PROGRESS` (or terminal — `COMPLETED`, `CANCELLED`,\n`EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 312,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' has already been activated\"\n}\n```\n\n### 400 Bad Request - Bonus Eligibility Activate Rules Not Satisfied\n\nMaps to the legacy `bonus.activate_rules_not_completely_satisfied` domain code.\nOccurs when the bonus has activate-time rules (e.g. required deposits, identity\nverification) that are not yet satisfied at activation time.\n\n```json\n{\n    \"errorCode\": 313,\n    \"errorMessage\": \"Eligibility activate rules are not satisfied for bonus '0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **No-op for auto-activating bonuses.** When the underlying bonus has\n   `isAutoActivates: true`, calling activate after a successful claim returns\n   `PLAYER_BONUS_ALREADY_ACTIVATED` (312). Partners can skip the activate step\n   entirely for these bonuses — branch on the catalogue-side `isAutoActivates` flag.\n\n2. **Activation initiator.** The action is recorded with `ActivatePlayerBonusInitiator\n   = SYSTEM`, matching the value used by Sumstats's internal auto-activation logic.\n   This is intentional — the partner integration is treated as a system actor, not\n   as an operator user.\n\n3. **Activate-time rules.** A free-bet bonus may have separate activate-time rules\n   (`eligibility.activateRules`) on top of claim-time rules. For example, a bonus\n   may be claimable on registration but require a qualifying deposit before it can\n   be activated. The `BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED` (313) error\n   surfaces this case.\n\n4. **Activation deadline.** If the bonus is `CLAIMED` past its `expiredOnClaimAt`\n   timestamp, activation fails with `PLAYER_BONUS_NOT_FOUND` (310) because the\n   engine transitions the player bonus to `EXPIRED` automatically.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Player bonus not found for externalUserId='ext_987654321' and bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}"}],"_postman_id":"8f24f67f-e4e9-4b9c-9d48-41ee2da4a6fc"},{"name":"Cancel Player Bonus","id":"37ec56b3-bc9c-49c6-9d4a-a9b06f0491d1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/cancel-player-bonus","description":"<h1 id=\"endpoint-for-cancelling-a-player-bonus\">Endpoint for Cancelling a Player Bonus</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/bonus/cancel-player-bonus</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint cancels an active <strong>internal sportsbook free-bet</strong> player bonus\nidentified by the external player id and the bonus id. Use it when your side decides\nto revoke a previously claimed (or in-progress) free bet — for example after a fraud\nsignal, a duplicate-account match, or a partner-side policy change.</p>\n<p>The cancellation is recorded in the bonus action history as a\n<code>CancelledBySystemDetails</code> entry (<code>actionType: CANCELLED_BY_SYSTEM</code>) with the calling\n<code>brandId</code> captured in the action <code>reason</code> field for audit traceability — <strong>no\noperator id is involved</strong>. The player bonus moves to <code>status: \"CANCELLED\"</code>,\n<code>finishedAt</code> is set to the cancellation timestamp, and the bonus engine notifies the\npayment service to claw back any awarded free-bet balance from the bonus wallet.</p>\n<p>Already-completed, already-cancelled, expired, or lost player bonuses cannot be\ncancelled and surface as <code>PLAYER_BONUS_NOT_CANCELLABLE</code> (311). The integration\npre-filters to <code>CLAIMED</code> and <code>IN_PROGRESS</code> statuses, so this error is normally only\nseen in a tight TOCTOU race where the player bonus completes between filter and\nvalidate.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>brandId</strong> (integer, required) - Brand id provided by Sumstats. Must match the\nbrand encoded in the HTTP Basic credentials. Captured in the action history\n<code>reason</code> field for traceability.</p>\n</li>\n<li><p><strong>brand</strong> (string, optional) - Deprecated alias for <code>brandId</code>. Accepted during the\nbrand migration window only.</p>\n</li>\n<li><p><strong>externalUserId</strong> (string, required) - External player id in the operator system.\nCannot be blank.</p>\n</li>\n<li><p><strong>bonusId</strong> (string, required) - UUID of the bonus whose active player-bonus should\nbe cancelled. Must match a <code>CLAIMED</code> or <code>IN_PROGRESS</code> player-bonus for the player.\nCannot be blank.</p>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><strong>playerBonus</strong> (object, required) - The cancelled player bonus. Same slim shape\ndocumented under <a href=\"#endpoint-for-finding-player-bonuses\">Find Player Bonuses</a>.\nNotable fields after a successful cancel:</p>\n<ul>\n<li><strong>status</strong> (enum, required) - <code>\"CANCELLED\"</code>.</li>\n<li><strong>finishedAt</strong> (long, required) - Cancellation timestamp (epoch millis, UTC).</li>\n<li><strong>bonusGiven</strong> (object, optional) - Reflects the free-bet balance at\ncancellation time; the actual claw-back happens asynchronously via the\npayment-service notification. For player bonuses cancelled while in <code>CLAIMED</code>\n(no money credited yet), this is <code>null</code>.</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"request-example\">Request Example</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n</code></pre>\n<h2 id=\"response-examples\">Response Examples</h2>\n<h3 id=\"successful-response-200-ok--cancel-of-an-in-progress-free-bet\">Successful Response (200 OK) — Cancel of an in-progress free bet</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n</code></pre>\n<h3 id=\"successful-response-200-ok--cancel-of-a-claimed-not-yet-activated-free-bet\">Successful Response (200 OK) — Cancel of a claimed (not-yet-activated) free bet</h3>\n<p>When the player bonus is <code>CLAIMED</code> (no money credited yet), <code>bonusGiven</code> is <code>null</code>\nand there is no claw-back side effect. <code>finishedAt</code> is set; <code>activatedAt</code> stays\n<code>null</code>.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n</code></pre>\n<h2 id=\"error-responses\">Error Responses</h2>\n<h3 id=\"400-bad-request---request-validation-error\">400 Bad Request - Request Validation Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---invalid-user\">400 Bad Request - Invalid User</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---player-bonus-not-found\">400 Bad Request - Player Bonus Not Found</h3>\n<p>Occurs when no active player bonus (<code>CLAIMED</code> or <code>IN_PROGRESS</code>) matches the\n(<code>externalUserId</code>, <code>bonusId</code>) pair. Common causes:</p>\n<ul>\n<li>The player never claimed this bonus.</li>\n<li>The previously-claimed player bonus already finished (<code>COMPLETED</code>, <code>CANCELLED</code>,\n<code>EXPIRED</code>, <code>LOST</code>).</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n</code></pre>\n<h3 id=\"400-bad-request---player-bonus-not-cancellable\">400 Bad Request - Player Bonus Not Cancellable</h3>\n<p>Maps to the legacy <code>player_bonus.already_cancelled</code> / <code>player_bonus.already_finished</code>\ndomain codes. Occurs in a TOCTOU race between filter and validate when the player\nbonus completes between the find-cancellable lookup and the aggregate-side\nvalidation.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}\n</code></pre>\n<h3 id=\"401-unauthorized---invalid-credentials\">401 Unauthorized - Invalid Credentials</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n</code></pre>\n<h3 id=\"500-internal-server-error---unknown-error\">500 Internal Server Error - Unknown Error</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n</code></pre>\n<h2 id=\"important-notes\">Important Notes</h2>\n<ol>\n<li><p><strong>System-initiated cancel — no operator id.</strong> The cancellation is attributed to\nthe integration as <code>CANCELLED_BY_SYSTEM</code>, <strong>not</strong> to a specific operator. The\ncalling <code>brandId</code> is captured in the action <code>reason</code> for traceability. Internal\nadmin-side filtering on operator id will not surface these cancels — use the\naction type filter instead.</p>\n</li>\n<li><p><strong>Async claw-back.</strong> When the player bonus is <code>IN_PROGRESS</code> and has <code>bonusGiven</code>\npopulated, the cancel triggers a payment-service notification to claw back the\nfree-bet balance from the bonus wallet. The notification is processed\nasynchronously — the response returns as soon as the bonus aggregate's\n<code>CANCELLED</code> event is committed, not after the wallet update. Partners observing\nwallet-side state may see a small eventual-consistency window.</p>\n</li>\n<li><p><strong>Multiple active player bonuses for the same bonusId.</strong> When the player has\nmultiple <code>CLAIMED</code>/<code>IN_PROGRESS</code> player bonuses for the same bonus (rare —\nusually prevented by the catalogue-side claim limits), the integration cancels\nthe <strong>first matching</strong> entry. The contract is intentionally simple — partners\nthat need to target a specific player-bonus instance should call admin-side APIs.</p>\n</li>\n<li><p><strong>Idempotency.</strong> The endpoint is <strong>not</strong> idempotent. A second cancel call for an\nalready-cancelled player bonus returns <code>PLAYER_BONUS_NOT_FOUND</code> (310) (since the\nintegration filters by <code>CLAIMED</code>/<code>IN_PROGRESS</code>), not a success.</p>\n</li>\n</ol>\n<h2 id=\"authentication\">Authentication</h2>\n<p>This endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">Authorization: Basic base64(username:password)\nContent-Type: application/json\n</code></pre>\n<p>Use the <code>brandId</code> body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request <code>brandId</code> matches.</p>\n","urlObject":{"path":["external-casino-client","v1","bonus","cancel-player-bonus"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"8d0abffa-58f3-4448-b239-3cf49b7e136b","name":"success — Cancel of an in-progress free bet","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/cancel-player-bonus","description":"# Endpoint for Cancelling a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/cancel-player-bonus`\n\n## Description\n\nThis endpoint cancels an active **internal sportsbook free-bet** player bonus\nidentified by the external player id and the bonus id. Use it when your side decides\nto revoke a previously claimed (or in-progress) free bet — for example after a fraud\nsignal, a duplicate-account match, or a partner-side policy change.\n\nThe cancellation is recorded in the bonus action history as a\n`CancelledBySystemDetails` entry (`actionType: CANCELLED_BY_SYSTEM`) with the calling\n`brandId` captured in the action `reason` field for audit traceability — **no\noperator id is involved**. The player bonus moves to `status: \"CANCELLED\"`,\n`finishedAt` is set to the cancellation timestamp, and the bonus engine notifies the\npayment service to claw back any awarded free-bet balance from the bonus wallet.\n\nAlready-completed, already-cancelled, expired, or lost player bonuses cannot be\ncancelled and surface as `PLAYER_BONUS_NOT_CANCELLABLE` (311). The integration\npre-filters to `CLAIMED` and `IN_PROGRESS` statuses, so this error is normally only\nseen in a tight TOCTOU race where the player bonus completes between filter and\nvalidate.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials. Captured in the action history\n  `reason` field for traceability.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose active player-bonus should\n  be cancelled. Must match a `CLAIMED` or `IN_PROGRESS` player-bonus for the player.\n  Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The cancelled player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful cancel:\n\n  - **status** (enum, required) - `\"CANCELLED\"`.\n  - **finishedAt** (long, required) - Cancellation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, optional) - Reflects the free-bet balance at\n    cancellation time; the actual claw-back happens asynchronously via the\n    payment-service notification. For player bonuses cancelled while in `CLAIMED`\n    (no money credited yet), this is `null`.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Cancel of an in-progress free bet\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Cancel of a claimed (not-yet-activated) free bet\n\nWhen the player bonus is `CLAIMED` (no money credited yet), `bonusGiven` is `null`\nand there is no claw-back side effect. `finishedAt` is set; `activatedAt` stays\n`null`.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no active player bonus (`CLAIMED` or `IN_PROGRESS`) matches the\n(`externalUserId`, `bonusId`) pair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus already finished (`COMPLETED`, `CANCELLED`,\n  `EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Cancellable\n\nMaps to the legacy `player_bonus.already_cancelled` / `player_bonus.already_finished`\ndomain codes. Occurs in a TOCTOU race between filter and validate when the player\nbonus completes between the find-cancellable lookup and the aggregate-side\nvalidation.\n\n```json\n{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **System-initiated cancel — no operator id.** The cancellation is attributed to\n   the integration as `CANCELLED_BY_SYSTEM`, **not** to a specific operator. The\n   calling `brandId` is captured in the action `reason` for traceability. Internal\n   admin-side filtering on operator id will not surface these cancels — use the\n   action type filter instead.\n\n2. **Async claw-back.** When the player bonus is `IN_PROGRESS` and has `bonusGiven`\n   populated, the cancel triggers a payment-service notification to claw back the\n   free-bet balance from the bonus wallet. The notification is processed\n   asynchronously — the response returns as soon as the bonus aggregate's\n   `CANCELLED` event is committed, not after the wallet update. Partners observing\n   wallet-side state may see a small eventual-consistency window.\n\n3. **Multiple active player bonuses for the same bonusId.** When the player has\n   multiple `CLAIMED`/`IN_PROGRESS` player bonuses for the same bonus (rare —\n   usually prevented by the catalogue-side claim limits), the integration cancels\n   the **first matching** entry. The contract is intentionally simple — partners\n   that need to target a specific player-bonus instance should call admin-side APIs.\n\n4. **Idempotency.** The endpoint is **not** idempotent. A second cancel call for an\n   already-cancelled player bonus returns `PLAYER_BONUS_NOT_FOUND` (310) (since the\n   integration filters by `CLAIMED`/`IN_PROGRESS`), not a success.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}"},{"id":"98348dc2-765c-4596-93c8-e2f74095a5a8","name":"success — Cancel of a CLAIMED free bet","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/cancel-player-bonus","description":"# Endpoint for Cancelling a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/cancel-player-bonus`\n\n## Description\n\nThis endpoint cancels an active **internal sportsbook free-bet** player bonus\nidentified by the external player id and the bonus id. Use it when your side decides\nto revoke a previously claimed (or in-progress) free bet — for example after a fraud\nsignal, a duplicate-account match, or a partner-side policy change.\n\nThe cancellation is recorded in the bonus action history as a\n`CancelledBySystemDetails` entry (`actionType: CANCELLED_BY_SYSTEM`) with the calling\n`brandId` captured in the action `reason` field for audit traceability — **no\noperator id is involved**. The player bonus moves to `status: \"CANCELLED\"`,\n`finishedAt` is set to the cancellation timestamp, and the bonus engine notifies the\npayment service to claw back any awarded free-bet balance from the bonus wallet.\n\nAlready-completed, already-cancelled, expired, or lost player bonuses cannot be\ncancelled and surface as `PLAYER_BONUS_NOT_CANCELLABLE` (311). The integration\npre-filters to `CLAIMED` and `IN_PROGRESS` statuses, so this error is normally only\nseen in a tight TOCTOU race where the player bonus completes between filter and\nvalidate.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials. Captured in the action history\n  `reason` field for traceability.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose active player-bonus should\n  be cancelled. Must match a `CLAIMED` or `IN_PROGRESS` player-bonus for the player.\n  Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The cancelled player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful cancel:\n\n  - **status** (enum, required) - `\"CANCELLED\"`.\n  - **finishedAt** (long, required) - Cancellation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, optional) - Reflects the free-bet balance at\n    cancellation time; the actual claw-back happens asynchronously via the\n    payment-service notification. For player bonuses cancelled while in `CLAIMED`\n    (no money credited yet), this is `null`.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Cancel of an in-progress free bet\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Cancel of a claimed (not-yet-activated) free bet\n\nWhen the player bonus is `CLAIMED` (no money credited yet), `bonusGiven` is `null`\nand there is no claw-back side effect. `finishedAt` is set; `activatedAt` stays\n`null`.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no active player bonus (`CLAIMED` or `IN_PROGRESS`) matches the\n(`externalUserId`, `bonusId`) pair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus already finished (`COMPLETED`, `CANCELLED`,\n  `EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Cancellable\n\nMaps to the legacy `player_bonus.already_cancelled` / `player_bonus.already_finished`\ndomain codes. Occurs in a TOCTOU race between filter and validate when the player\nbonus completes between the find-cancellable lookup and the aggregate-side\nvalidation.\n\n```json\n{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **System-initiated cancel — no operator id.** The cancellation is attributed to\n   the integration as `CANCELLED_BY_SYSTEM`, **not** to a specific operator. The\n   calling `brandId` is captured in the action `reason` for traceability. Internal\n   admin-side filtering on operator id will not surface these cancels — use the\n   action type filter instead.\n\n2. **Async claw-back.** When the player bonus is `IN_PROGRESS` and has `bonusGiven`\n   populated, the cancel triggers a payment-service notification to claw back the\n   free-bet balance from the bonus wallet. The notification is processed\n   asynchronously — the response returns as soon as the bonus aggregate's\n   `CANCELLED` event is committed, not after the wallet update. Partners observing\n   wallet-side state may see a small eventual-consistency window.\n\n3. **Multiple active player bonuses for the same bonusId.** When the player has\n   multiple `CLAIMED`/`IN_PROGRESS` player bonuses for the same bonus (rare —\n   usually prevented by the catalogue-side claim limits), the integration cancels\n   the **first matching** entry. The contract is intentionally simple — partners\n   that need to target a specific player-bonus instance should call admin-side APIs.\n\n4. **Idempotency.** The endpoint is **not** idempotent. A second cancel call for an\n   already-cancelled player bonus returns `PLAYER_BONUS_NOT_FOUND` (310) (since the\n   integration filters by `CLAIMED`/`IN_PROGRESS`), not a success.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}"},{"id":"a3bce8ef-1dd0-4046-99a2-8e36529ef612","name":"fail — player bonus not found (310)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/cancel-player-bonus","description":"# Endpoint for Cancelling a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/cancel-player-bonus`\n\n## Description\n\nThis endpoint cancels an active **internal sportsbook free-bet** player bonus\nidentified by the external player id and the bonus id. Use it when your side decides\nto revoke a previously claimed (or in-progress) free bet — for example after a fraud\nsignal, a duplicate-account match, or a partner-side policy change.\n\nThe cancellation is recorded in the bonus action history as a\n`CancelledBySystemDetails` entry (`actionType: CANCELLED_BY_SYSTEM`) with the calling\n`brandId` captured in the action `reason` field for audit traceability — **no\noperator id is involved**. The player bonus moves to `status: \"CANCELLED\"`,\n`finishedAt` is set to the cancellation timestamp, and the bonus engine notifies the\npayment service to claw back any awarded free-bet balance from the bonus wallet.\n\nAlready-completed, already-cancelled, expired, or lost player bonuses cannot be\ncancelled and surface as `PLAYER_BONUS_NOT_CANCELLABLE` (311). The integration\npre-filters to `CLAIMED` and `IN_PROGRESS` statuses, so this error is normally only\nseen in a tight TOCTOU race where the player bonus completes between filter and\nvalidate.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials. Captured in the action history\n  `reason` field for traceability.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose active player-bonus should\n  be cancelled. Must match a `CLAIMED` or `IN_PROGRESS` player-bonus for the player.\n  Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The cancelled player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful cancel:\n\n  - **status** (enum, required) - `\"CANCELLED\"`.\n  - **finishedAt** (long, required) - Cancellation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, optional) - Reflects the free-bet balance at\n    cancellation time; the actual claw-back happens asynchronously via the\n    payment-service notification. For player bonuses cancelled while in `CLAIMED`\n    (no money credited yet), this is `null`.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Cancel of an in-progress free bet\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Cancel of a claimed (not-yet-activated) free bet\n\nWhen the player bonus is `CLAIMED` (no money credited yet), `bonusGiven` is `null`\nand there is no claw-back side effect. `finishedAt` is set; `activatedAt` stays\n`null`.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no active player bonus (`CLAIMED` or `IN_PROGRESS`) matches the\n(`externalUserId`, `bonusId`) pair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus already finished (`COMPLETED`, `CANCELLED`,\n  `EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Cancellable\n\nMaps to the legacy `player_bonus.already_cancelled` / `player_bonus.already_finished`\ndomain codes. Occurs in a TOCTOU race between filter and validate when the player\nbonus completes between the find-cancellable lookup and the aggregate-side\nvalidation.\n\n```json\n{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **System-initiated cancel — no operator id.** The cancellation is attributed to\n   the integration as `CANCELLED_BY_SYSTEM`, **not** to a specific operator. The\n   calling `brandId` is captured in the action `reason` for traceability. Internal\n   admin-side filtering on operator id will not surface these cancels — use the\n   action type filter instead.\n\n2. **Async claw-back.** When the player bonus is `IN_PROGRESS` and has `bonusGiven`\n   populated, the cancel triggers a payment-service notification to claw back the\n   free-bet balance from the bonus wallet. The notification is processed\n   asynchronously — the response returns as soon as the bonus aggregate's\n   `CANCELLED` event is committed, not after the wallet update. Partners observing\n   wallet-side state may see a small eventual-consistency window.\n\n3. **Multiple active player bonuses for the same bonusId.** When the player has\n   multiple `CLAIMED`/`IN_PROGRESS` player bonuses for the same bonus (rare —\n   usually prevented by the catalogue-side claim limits), the integration cancels\n   the **first matching** entry. The contract is intentionally simple — partners\n   that need to target a specific player-bonus instance should call admin-side APIs.\n\n4. **Idempotency.** The endpoint is **not** idempotent. A second cancel call for an\n   already-cancelled player bonus returns `PLAYER_BONUS_NOT_FOUND` (310) (since the\n   integration filters by `CLAIMED`/`IN_PROGRESS`), not a success.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}"},{"id":"e71815d5-8732-4981-b027-142ed9f9c677","name":"fail — not cancellable (311)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"externalUserId\": \"ext_987654321\",\n    \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/bonus/cancel-player-bonus","description":"# Endpoint for Cancelling a Player Bonus\n\n## Endpoint\n\n**POST** `/external-casino-client/v1/bonus/cancel-player-bonus`\n\n## Description\n\nThis endpoint cancels an active **internal sportsbook free-bet** player bonus\nidentified by the external player id and the bonus id. Use it when your side decides\nto revoke a previously claimed (or in-progress) free bet — for example after a fraud\nsignal, a duplicate-account match, or a partner-side policy change.\n\nThe cancellation is recorded in the bonus action history as a\n`CancelledBySystemDetails` entry (`actionType: CANCELLED_BY_SYSTEM`) with the calling\n`brandId` captured in the action `reason` field for audit traceability — **no\noperator id is involved**. The player bonus moves to `status: \"CANCELLED\"`,\n`finishedAt` is set to the cancellation timestamp, and the bonus engine notifies the\npayment service to claw back any awarded free-bet balance from the bonus wallet.\n\nAlready-completed, already-cancelled, expired, or lost player bonuses cannot be\ncancelled and surface as `PLAYER_BONUS_NOT_CANCELLABLE` (311). The integration\npre-filters to `CLAIMED` and `IN_PROGRESS` statuses, so this error is normally only\nseen in a tight TOCTOU race where the player bonus completes between filter and\nvalidate.\n\n## Request Body Description\n\n**Object:**\n\n- **brandId** (integer, required) - Brand id provided by Sumstats. Must match the\n  brand encoded in the HTTP Basic credentials. Captured in the action history\n  `reason` field for traceability.\n\n- **brand** (string, optional) - Deprecated alias for `brandId`. Accepted during the\n  brand migration window only.\n\n- **externalUserId** (string, required) - External player id in the operator system.\n  Cannot be blank.\n\n- **bonusId** (string, required) - UUID of the bonus whose active player-bonus should\n  be cancelled. Must match a `CLAIMED` or `IN_PROGRESS` player-bonus for the player.\n  Cannot be blank.\n\n## Response Body Description\n\n**Object:**\n\n- **playerBonus** (object, required) - The cancelled player bonus. Same slim shape\n  documented under [Find Player Bonuses](#endpoint-for-finding-player-bonuses).\n  Notable fields after a successful cancel:\n\n  - **status** (enum, required) - `\"CANCELLED\"`.\n  - **finishedAt** (long, required) - Cancellation timestamp (epoch millis, UTC).\n  - **bonusGiven** (object, optional) - Reflects the free-bet balance at\n    cancellation time; the actual claw-back happens asynchronously via the\n    payment-service notification. For player bonuses cancelled while in `CLAIMED`\n    (no money credited yet), this is `null`.\n\n## Request Example\n\n```json\n{\n  \"brandId\": 0,\n  \"externalUserId\": \"ext_987654321\",\n  \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\"\n}\n```\n\n## Response Examples\n\n### Successful Response (200 OK) — Cancel of an in-progress free bet\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": 1761724805143,\n        \"finishedAt\": 1761728405143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": true,\n        \"bonusGiven\": {\n            \"amount\": \"50000\",\n            \"currency\": \"TRY\"\n        },\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n### Successful Response (200 OK) — Cancel of a claimed (not-yet-activated) free bet\n\nWhen the player bonus is `CLAIMED` (no money credited yet), `bonusGiven` is `null`\nand there is no claw-back side effect. `finishedAt` is set; `activatedAt` stays\n`null`.\n\n```json\n{\n    \"playerBonus\": {\n        \"id\": \"0192f730-ceb0-78d2-a4ba-156107b9dbf8\",\n        \"bonusId\": \"0192f721-29ae-7aef-9688-7c8bc5508b88\",\n        \"bonusName\": [\n            {\n                \"locale\": \"en_US\",\n                \"translate\": \"500 TRY FREE BET\"\n            }\n        ],\n        \"bonusType\": \"INTERNAL_FREE_BET\",\n        \"status\": \"CANCELLED\",\n        \"externalPlayerId\": \"ext_987654321\",\n        \"createdAt\": 1761721205143,\n        \"activatedAt\": null,\n        \"finishedAt\": 1761725005143,\n        \"expiredAt\": null,\n        \"expiredOnClaimAt\": 1762326005143,\n        \"isAutoActivates\": false,\n        \"bonusGiven\": null,\n        \"totalWagering\": null,\n        \"currency\": \"TRY\"\n    }\n}\n```\n\n## Error Responses\n\n### 400 Bad Request - Request Validation Error\n\n```json\n{\n    \"errorCode\": 3,\n    \"errorMessage\": \"'bonusId' is not a valid UUID: 'foo'\"\n}\n```\n\n### 400 Bad Request - Invalid User\n\n```json\n{\n    \"errorCode\": 109,\n    \"errorMessage\": \"External player 'ext_987654321' could not be resolved\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Found\n\nOccurs when no active player bonus (`CLAIMED` or `IN_PROGRESS`) matches the\n(`externalUserId`, `bonusId`) pair. Common causes:\n\n- The player never claimed this bonus.\n- The previously-claimed player bonus already finished (`COMPLETED`, `CANCELLED`,\n  `EXPIRED`, `LOST`).\n\n```json\n{\n    \"errorCode\": 310,\n    \"errorMessage\": \"Active player bonus not found for externalUserId='ext_987654321', bonusId='0192f721-29ae-7aef-9688-7c8bc5508b88'\"\n}\n```\n\n### 400 Bad Request - Player Bonus Not Cancellable\n\nMaps to the legacy `player_bonus.already_cancelled` / `player_bonus.already_finished`\ndomain codes. Occurs in a TOCTOU race between filter and validate when the player\nbonus completes between the find-cancellable lookup and the aggregate-side\nvalidation.\n\n```json\n{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}\n```\n\n### 401 Unauthorized - Invalid Credentials\n\n```json\n{\n    \"errorCode\": 2,\n    \"errorMessage\": \"Invalid credentials\"\n}\n```\n\n### 500 Internal Server Error - Unknown Error\n\n```json\n{\n    \"errorCode\": 1,\n    \"errorMessage\": \"Unknown error\"\n}\n```\n\n## Important Notes\n\n1. **System-initiated cancel — no operator id.** The cancellation is attributed to\n   the integration as `CANCELLED_BY_SYSTEM`, **not** to a specific operator. The\n   calling `brandId` is captured in the action `reason` for traceability. Internal\n   admin-side filtering on operator id will not surface these cancels — use the\n   action type filter instead.\n\n2. **Async claw-back.** When the player bonus is `IN_PROGRESS` and has `bonusGiven`\n   populated, the cancel triggers a payment-service notification to claw back the\n   free-bet balance from the bonus wallet. The notification is processed\n   asynchronously — the response returns as soon as the bonus aggregate's\n   `CANCELLED` event is committed, not after the wallet update. Partners observing\n   wallet-side state may see a small eventual-consistency window.\n\n3. **Multiple active player bonuses for the same bonusId.** When the player has\n   multiple `CLAIMED`/`IN_PROGRESS` player bonuses for the same bonus (rare —\n   usually prevented by the catalogue-side claim limits), the integration cancels\n   the **first matching** entry. The contract is intentionally simple — partners\n   that need to target a specific player-bonus instance should call admin-side APIs.\n\n4. **Idempotency.** The endpoint is **not** idempotent. A second cancel call for an\n   already-cancelled player bonus returns `PLAYER_BONUS_NOT_FOUND` (310) (since the\n   integration filters by `CLAIMED`/`IN_PROGRESS`), not a success.\n\n## Authentication\n\nThis endpoint requires HTTP Basic authentication. Per-brand credentials are issued by\nSumstats Support and configured via the operator dashboard. Calls also pass an IP\nwhitelist — requests originating outside the allow-listed IPs are rejected at the\ngateway with HTTP 403.\n\n```http\nAuthorization: Basic base64(username:password)\nContent-Type: application/json\n```\n\nUse the `brandId` body field together with the credentials — Sumstats resolves the brand\nfrom the credentials and validates that the request `brandId` matches.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 311,\n    \"errorMessage\": \"Player bonus '0192f730-ceb0-78d2-a4ba-156107b9dbf8' cannot be cancelled: already finished\"\n}"}],"_postman_id":"37ec56b3-bc9c-49c6-9d4a-a9b06f0491d1"}],"id":"51b93457-2ea9-4302-a12b-94d1ce7cac9b","description":"<p>Requests sent from Casino to Aggregator Provider for the <strong>internal sportsbook free-bet</strong> Bonus integration. Use these endpoints to discover available free bets, claim/activate/cancel them on behalf of an external player, and inspect a player's current free-bet bonuses. See the Bonus API folder description above for shared conventions (auth, real schema values, polymorphic payloads, MoneyBag, error code families).</p>\n","_postman_id":"51b93457-2ea9-4302-a12b-94d1ce7cac9b"}],"id":"d2450151-9b90-486e-8d02-3e7f48290cc6","description":"<h1 id=\"bonus-api\">Bonus API</h1>\n<p>Aggregator-bound Bonus integration purpose-built for <strong><code>INTERNAL_FREE_BET</code> bonuses on the sportsbook product</strong> (<code>InternalFreeBetSportsbookCriteria</code> payload) — discover free bets available for a player, claim/activate/cancel them on behalf of an external player, and inspect the player's current free-bet state.</p>\n<blockquote>\n<p><strong>Scope.</strong> This integration covers internal sportsbook free-bet bonuses only. Other bonus types (<code>CUSTOM</code>, <code>FIRST_DEPOSIT</code>, <code>EXTERNAL_FREE_BET</code>, <code>EXTERNAL_FREE_SPINS_WITH_WAGERING</code>, <code>INTERNAL_FREE_SPINS_WITH_WAGERING</code>, <code>CASHBACK</code>) and non-sportsbook free-bet criteria (casino, live-casino, games, virtual) may exist in the operator catalogue but are out of scope for this contract — partners should filter responses to <code>bonusType: \"INTERNAL_FREE_BET\"</code> with <code>bonusSize.rule.productRules[0].criteria.__payloadKind: \"InternalFreeBetSportsbookCriteria\"</code> client-side. <code>winSize</code> and <code>wagering</code> are always <code>null</code> for free bets.</p>\n</blockquote>\n<h2 id=\"authentication--network\">Authentication &amp; Network</h2>\n<p>All endpoints share the HTTP Basic auth + per-brand IP whitelist used by the rest of the External Casino Client surface. Per-brand credentials are issued by Sumstats Support and configured via the operator dashboard. Calls from non-allowlisted IPs are rejected at the gateway with HTTP 403.</p>\n<p>Each request must carry:</p>\n<ul>\n<li><code>Authorization: Basic base64(username:password)</code></li>\n<li><code>Content-Type: application/json</code></li>\n<li><code>brandId</code> in the request body matching the brand encoded in the credentials.</li>\n</ul>\n<p>Endpoints are exposed under <code>https://ecp-api-&lt;env&gt;.&lt;domain&gt;/external-casino-client/v1/bonus/...</code>.</p>\n<h2 id=\"modeling-notes\">Modeling notes</h2>\n<ul>\n<li>Find Available Bonuses returns a slim free-bet catalogue object with the polymorphic <code>bonusSize</code> payload intact, so partners can render the offer faithfully. UI-only fields (descriptions, preview images, full T&amp;Cs), operator metadata (<code>operatorId</code>, <code>ruleIds</code>, <code>removedAt</code>, <code>updatedAt</code>), and share-limits routing are dropped.</li>\n<li>Find Player Bonuses / Claim / Activate / Cancel return a slim <code>playerBonus</code> shape with <code>bonusSnapshot</code> collapsed into <code>bonusId</code> + <code>bonusName</code> + <code>bonusType</code> and <code>bonusGiven</code> projected to plain <code>{amount, currency}</code> in the player's currency. <code>totalWagering</code> is always <code>null</code> for free bets.</li>\n<li>Cancel attributes the action to the integration as <code>CANCELLED_BY_SYSTEM</code> — no operator id involved. The calling <code>brandId</code> is captured in the action <code>reason</code> field for audit trails.</li>\n</ul>\n<h2 id=\"real-schema-values\">Real schema values</h2>\n<p>Sportsbook fields use real values from the generated <code>SportsbookSchema</code>:</p>\n<ul>\n<li><strong><code>betRule.betTypes</code></strong> — <code>BetHashType</code> enum, JSON-serialised lowercase via Jackson <code>@JsonProperty</code>. Possible values: <code>\"single\"</code>, <code>\"parlay\"</code> (accumulator), <code>\"system\"</code>. Note: <code>\"accumulator\"</code> is <strong>not</strong> a real value — the schema name for accumulator bets is <code>parlay</code>.</li>\n<li><strong><code>filters[].markets</code></strong> — <code>MarketType</code> enum from the generated SportsbookSchema, JSON-serialised as the lowercase enum name. Examples: <code>score_1x2</code>, <code>score_ou</code>, <code>score_dc</code>, <code>score_both_to_score_yes_no</code>, <code>score_ht_ft</code>, <code>score_winning_margin</code>, <code>score_exact_number</code>, <code>corner_1x2</code>, <code>yellow_card_1x2</code>, <code>red_card_1x2</code>. The set of valid market types is generated from the operator's sportsbook configuration.</li>\n<li><strong><code>sportId</code>, <code>categoryId</code>, <code>tournamentId</code>, <code>eventId</code></strong> — operator-defined UUIDs, not system enums. Partners must map these via their own catalogue synchronisation with the operator.</li>\n</ul>\n<h2 id=\"polymorphic-payloads\">Polymorphic payloads</h2>\n<p>Several response objects are polymorphic (sealed) hierarchies discriminated by an explicit <code>__payloadKind</code> string field. For the <code>INTERNAL_FREE_BET</code> sportsbook bonuses this integration handles, the relevant unions are:</p>\n<ul>\n<li><strong><code>bonusSize</code></strong> — always <code>FreeBetSize</code>.</li>\n<li><strong><code>bonusSize.amount</code></strong> (free-bet balance) — <code>MonetarySize</code> (fixed) or <code>PercentageSize</code> (rare for free bets).</li>\n<li><strong><code>bonusSize.rule.productRules[].criteria</code></strong> — always <code>InternalFreeBetSportsbookCriteria</code> for this contract.</li>\n<li><strong><code>bonusSize.rule.freeBetUseType</code></strong> — <code>FreeBetAllBalanceUseType</code> (stake = full free-bet balance) or <code>FreeBetPartialBalanceUseType</code> (stake mixes free-bet + real money).</li>\n</ul>\n<p>Partners must discriminate on <code>__payloadKind</code> — adding new payload kinds is the standard evolution path.</p>\n<h2 id=\"moneybag-shape\">MoneyBag shape</h2>\n<p>Examples in this document use only the <code>system</code> amount in a single currency:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"system\": { \"amount\": \"50000\", \"currency\": \"TRY\" },\n  \"additional\": []\n}\n</code></pre>\n<p><code>system</code> carries the amount in the bonus's currency. <code>additional</code> is the array of per-currency overrides for cross-currency bonuses — when the player's currency matches an entry's <code>currency</code>, the entry's <code>amount</code> is used directly; otherwise the <code>system</code> amount is converted via the operator's currency-pair rates. Single-currency bonuses (the common case) emit an empty <code>additional</code> array, as in all examples here. The <code>amount</code> is a string in raw integer minor-unit form (<code>\"50000\"</code> = 500.00 TRY) — partners should not assume floating-point representation.</p>\n<h2 id=\"error-code-conventions\">Error code conventions</h2>\n<p>Errors share the common ECP envelope <code>{ \"errorCode\": &lt;int&gt;, \"errorMessage\": &lt;string&gt; }</code>. Bonus-specific codes occupy the 300-range:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Constant</th>\n<th>Family</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>301</td>\n<td>BONUS_NOT_FOUND</td>\n<td>Bonus catalogue</td>\n</tr>\n<tr>\n<td>302</td>\n<td>BONUS_DISABLED</td>\n<td>Bonus catalogue</td>\n</tr>\n<tr>\n<td>303</td>\n<td>BONUS_NOT_AVAILABLE</td>\n<td>Bonus catalogue</td>\n</tr>\n<tr>\n<td>304</td>\n<td>BONUS_USER_LIMITS_EXCEEDED</td>\n<td>Limits</td>\n</tr>\n<tr>\n<td>305</td>\n<td>BONUS_TOTAL_LIMITS_EXCEEDED</td>\n<td>Limits</td>\n</tr>\n<tr>\n<td>306</td>\n<td>BONUS_ELIGIBILITY_CLAIM_RULES_NOT_SATISFIED</td>\n<td>Eligibility</td>\n</tr>\n<tr>\n<td>307</td>\n<td>PLAYER_BONUS_ALREADY_CLAIMED</td>\n<td>Player bonus</td>\n</tr>\n<tr>\n<td>308</td>\n<td>BONUS_ONE_PER_PLAYER_TAG_VIOLATION</td>\n<td>Tags</td>\n</tr>\n<tr>\n<td>309</td>\n<td>BONUS_NEW_CUSTOMER_TAG_VIOLATION</td>\n<td>Tags</td>\n</tr>\n<tr>\n<td>310</td>\n<td>PLAYER_BONUS_NOT_FOUND</td>\n<td>Player bonus</td>\n</tr>\n<tr>\n<td>311</td>\n<td>PLAYER_BONUS_NOT_CANCELLABLE</td>\n<td>Player bonus</td>\n</tr>\n<tr>\n<td>312</td>\n<td>PLAYER_BONUS_ALREADY_ACTIVATED</td>\n<td>Player bonus</td>\n</tr>\n<tr>\n<td>313</td>\n<td>BONUS_ELIGIBILITY_ACTIVATE_RULES_NOT_SATISFIED</td>\n<td>Eligibility</td>\n</tr>\n</tbody>\n</table>\n</div><p>Common ECP-level codes (<code>2 INVALID_CREDENTIALS</code>, <code>3 BAD_REQUEST</code>, <code>4 DESERIALIZATION_ERROR</code>, <code>109 INVALID_USER</code>, <code>1 UNKNOWN</code>) apply to all endpoints.</p>\n","_postman_id":"d2450151-9b90-486e-8d02-3e7f48290cc6"},{"name":"Error Response","item":[],"id":"37151abb-1eec-40c7-882f-90471da920b5","description":"<p>Error response from Casino to Aggregator Provider and vice versa is the same</p>\n<p>Status Code: <code>not 200</code></p>\n<h4 id=\"response-body-description\">Response Body Description:</h4>\n<p>Object:</p>\n<ul>\n<li><p><code>errorCode</code> (integer, required)</p>\n</li>\n<li><p><code>errorMessage</code> (string, reqiured)</p>\n</li>\n</ul>\n<p>Error Codes:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><strong>Code</strong></th>\n<th><strong>Reason</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>INTERNAL_SERVER_ERROR</td>\n</tr>\n<tr>\n<td>2</td>\n<td>INVALID_CREDENTIALS</td>\n</tr>\n<tr>\n<td>3</td>\n<td>BAD_REQUEST</td>\n</tr>\n<tr>\n<td>4</td>\n<td>DESERIALIZATION_ERROR</td>\n</tr>\n<tr>\n<td>5</td>\n<td>NETWORK_ERROR</td>\n</tr>\n<tr>\n<td>6</td>\n<td>TIMEOUT_ERROR</td>\n</tr>\n<tr>\n<td>101</td>\n<td>PROVIDER_NOT_ACTIVE</td>\n</tr>\n<tr>\n<td>102</td>\n<td>PROVIDER_ERROR</td>\n</tr>\n<tr>\n<td>103</td>\n<td>GAME_NOT_ACTIVE</td>\n</tr>\n<tr>\n<td>104</td>\n<td>GAME_NOT_FOUND</td>\n</tr>\n<tr>\n<td>105</td>\n<td>GAME_DEMO_NOT_SUPPORTED</td>\n</tr>\n<tr>\n<td>106</td>\n<td>USER_INSUFFICIENT_BALANCE</td>\n</tr>\n<tr>\n<td>107</td>\n<td>USER_CREATION_FAILED</td>\n</tr>\n<tr>\n<td>109</td>\n<td>INVALID_USER</td>\n</tr>\n<tr>\n<td>110</td>\n<td>DISABLED_USER</td>\n</tr>\n<tr>\n<td>111</td>\n<td>CURRENCY_NOT_SUPPORTED</td>\n</tr>\n<tr>\n<td>112</td>\n<td>USER_SESSION_EXPIRED</td>\n</tr>\n<tr>\n<td>113</td>\n<td>ROUND_HISTORY_NOT_SUPPORTED</td>\n</tr>\n<tr>\n<td>114</td>\n<td>FREE_SPINS_NOT_SUPPORTED</td>\n</tr>\n<tr>\n<td>115</td>\n<td>ROUND_NOT_FOUND</td>\n</tr>\n<tr>\n<td>116</td>\n<td>TRANSACTION_NOT_FOUND</td>\n</tr>\n<tr>\n<td>117</td>\n<td>PROVIDER_NOT_FOUND</td>\n</tr>\n<tr>\n<td>118</td>\n<td>LOBBY_DISABLED</td>\n</tr>\n<tr>\n<td>201</td>\n<td>ROLLED_BACK_TRANSACTION_NOT_FOUND</td>\n</tr>\n<tr>\n<td>202</td>\n<td>INVALID_ROLLED_BACK_TRANSACTION_TYPE</td>\n</tr>\n<tr>\n<td>203</td>\n<td>AFFILIATE_NOT_FOUND</td>\n</tr>\n<tr>\n<td>204</td>\n<td>AFFILIATE_LINK_NOT_FOUND</td>\n</tr>\n<tr>\n<td>205</td>\n<td>MISSING_TRACKING_CODE</td>\n</tr>\n<tr>\n<td>206</td>\n<td>INVALID_TRACKING_CODE_TOKEN</td>\n</tr>\n<tr>\n<td>207</td>\n<td>UNSUPPORTED_TRACKING_CODE_VERSION</td>\n</tr>\n<tr>\n<td>208</td>\n<td>MALFORMED_TRACKING_CODE</td>\n</tr>\n<tr>\n<td>209</td>\n<td>EXPIRED_TRACKING_CODE</td>\n</tr>\n<tr>\n<td>250</td>\n<td>DOMAIN_UPDATING_FAILED</td>\n</tr>\n</tbody>\n</table>\n</div><p>Response Example:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errorCode\": 2,\n  \"errorMessage\": \"Invalid credentials\"\n}\n\n</code></pre>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"8833b7d6-e08c-417d-a484-7e36436b22cd"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"037d69a1-416b-4c64-859c-80a1883d8b8e"}}],"_postman_id":"37151abb-1eec-40c7-882f-90471da920b5"},{"name":"General clarifications","item":[],"id":"78ddc1bc-a249-4151-b8b9-a27c4e170bcc","description":"<ol>\n<li><p>All responses to transaction callbacks must be idempotent</p>\n</li>\n<li><p>Rollback transaction callback can be both for bet and win transactions</p>\n</li>\n<li><p>Rollback transaction can be sent before transaction to rollback.<br /> In this case rollback should be accepted and if transaction to rollback came later, it should be accepted too and response should be successful.<br /> For both callbacks no balance changes must be processed</p>\n</li>\n<li><p>Average response time should be no more than 500 ms for good user experience. Request will be aborted if there is no response more than 5 seconds</p>\n</li>\n<li><p>In case of loss win with 0 amount will be sent</p>\n</li>\n<li><p>End round callback doesn't produce any transaction. It is notification about round end</p>\n</li>\n<li><p>Bets can be with amount 0</p>\n</li>\n<li><p>Bets with 0 amount are retriable</p>\n</li>\n<li><p>Bets with 0 amount must be always accepted</p>\n</li>\n<li><p>Bets with not 0 amount are not retriable. Failed bet will cause rollback on bet</p>\n</li>\n<li><p>Wins and Rollbacks are retriable</p>\n</li>\n<li><p>Wins and Rollbacks must be always accepted</p>\n</li>\n<li><p>If game has empty betValues, then it doesn't support free spins</p>\n</li>\n</ol>\n","auth":{"type":"noauth","isInherited":false},"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"93d3f271-30ef-43e6-b196-7fae9c7dacad"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"093cb173-e237-4cd5-adc6-cc45dd5ceee1"}}],"_postman_id":"78ddc1bc-a249-4151-b8b9-a27c4e170bcc"},{"name":"Domains API","item":[{"name":"Aggregator API","item":[{"name":"Update domain","id":"c0455d25-d76a-42b1-aae9-aba29abd39a4","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"domain\": {\n        \"type\": \"EXTERNAL\",\n        \"name\": \"example.com\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/domains/target/update","description":"<h1 id=\"endpoint-for-updating-casino-domain\">Endpoint for Updating Casino Domain</h1>\n<h2 id=\"endpoint\">Endpoint</h2>\n<p><strong>POST</strong> <code>/external-casino-client/v1/domains/target/update</code></p>\n<h2 id=\"description\">Description</h2>\n<p>This endpoint allows external casino systems to change the current domain value of a casino. Traffic is redirected to this domain, which serves as the target for incoming traffic across various system components.</p>\n<h2 id=\"request-body-description\">Request Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><code>brandId</code> (integer, required) - Brand id provided by aggregator provider. Must be a valid brand identifier.</p>\n</li>\n<li><p><code>domain</code> (string, required) - Domain to update.</p>\n<ul>\n<li><p><code>type</code> (enum, required) - Domain type. Valid values:</p>\n<ul>\n<li><code>EXTERNAL</code> - External type.</li>\n</ul>\n</li>\n<li><p><code>name</code> (string, required) - Domain name. Must be a valid domain name (for example <code>example.com</code>).</p>\n</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"response-body-description\">Response Body Description</h2>\n<p><strong>Object:</strong></p>\n<ul>\n<li><p><code>brandId</code> (integer, required) - Brand id provided by aggregator provider.</p>\n</li>\n<li><p><code>domain</code> (object, required) - Updated domain. This is the domain that was successfully updated in the system.</p>\n<ul>\n<li><p><code>type</code> (enum, required) - Domain type.</p>\n</li>\n<li><p><code>name</code> (string, required) - Updated domain name.</p>\n</li>\n</ul>\n</li>\n</ul>\n","urlObject":{"path":["external-casino-client","v1","domains","target","update"],"host":["{apiUrl}"],"query":[],"variable":[]}},"response":[{"id":"5a18d450-225f-41f5-b66c-f3cbc3999507","name":"success","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"domain\": {\n        \"type\": \"EXTERNAL\",\n        \"name\": \"example.com\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/domains/target/update"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"brandId\": 0,\n    \"domain\": \"example.com\"\n}"},{"id":"1bc2a25d-44f0-4c0e-b2b5-0e73b397330e","name":"fail","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n    \"brandId\": 0,\n    \"domain\": {\n        \"type\": \"EXTERNAL\",\n        \"name\": \"example.com\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"{apiUrl}/external-casino-client/v1/domains/target/update"},"status":"Internal Server Error","code":500,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json","description":"","type":"text"}],"cookie":[],"responseTime":null,"body":"{\n    \"errorCode\": 250,\n    \"errorMessage\": \"Failed to update domain\"\n}"}],"_postman_id":"c0455d25-d76a-42b1-aae9-aba29abd39a4"}],"id":"eb06b2b9-0a35-4e68-a8f6-88314e9653eb","_postman_id":"eb06b2b9-0a35-4e68-a8f6-88314e9653eb","description":""}],"id":"40b0ff50-1a68-4bdf-ac3b-a048f138f799","_postman_id":"40b0ff50-1a68-4bdf-ac3b-a048f138f799","description":""}],"event":[{"listen":"prerequest","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"9092af26-aa99-4c41-91b7-7f3a52947bfc"}},{"listen":"test","script":{"type":"text/javascript","packages":{},"exec":[""],"id":"ebf2b095-7f7b-4f73-ac3d-504f0d588229"}}],"variable":[{"key":"apiUrl","value":"{apiUrl}"},{"key":"username","value":"{username}"},{"key":"password","value":"{password}"},{"key":"callbackUrl","value":"{callbackUrl}"}]}