Bonus play API
Overview
The FreePlay API provides endpoints for managing free play tickets for both Classic games and Slot games. The API supports assignment, listing, revocation, and game information retrieval operations.
Authentication & Security
Headers
Required for all endpoints:
| Header | Type | Description |
|---|---|---|
X-OPERATOR
|
string | Partner code/identifier |
X-TIMESTAMP
|
string | ISO 8601 timestamp |
X-SIGNATURE
|
string | HMAC-SHA256 signature, base64 encoded |
Content-Type
|
string | application/json for POST requests
|
Signature Generation
Signature payload format: {partnerId}|{secretKey}|{timestamp}|{param1}|{param2}|...
Algorithm: HMAC-SHA256
Encoding: Base64
Example signature generation:
$payload = implode('|', [$partnerId, $secretKey, $timestamp, $playerId, $gameId, $serial]);
$signature = base64_encode(hash_hmac('sha256', $payload, $secretKey, true));
Assign Free Play
Endpoint
POST /s/bonus/freeplay/assign
Description
Assigns free play tickets to a player.
Request Body
{
"playerId": "player123",
"gameId": "1",
"serial": "UNIQUE-SERIAL-001",
"currency": "EUR",
"stake": "1.00",
"count": 1,
"expires": "2026-12-31T23:59:59+00:00",
"minOddValue": 1.00,
"maxOddValue": 100.00
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
playerId
|
string | Yes | External player identifier |
gameId
|
string | Yes | Game ID |
serial
|
string | Yes | Unique serial number for this assignment |
currency
|
string | Yes | ISO 4217 currency code |
stake
|
decimal | Yes | Stake amount per ticket/bet |
count
|
integer | Yes | Number of tickets/bets to assign. Supported only by slot games. For Classic games, always 1.
|
expires
|
string | Optional | Expiry date of the free play package. Can be provided as ISO 8601 UTC datetime string or Unix timestamp in seconds. If not set, the expiry date defaults to 180 days after the request is submitted. |
minOddValue
|
decimal | Optional | Minimum odd value required to place a free bet, applicable for Classic games. If not set, the default value is 1.
|
maxOddValue
|
decimal | Optional | Maximum odd value required to place a free bet, applicable for Classic games. If not set, there are no limitations. |
Signature Parameters
{partnerId}|{secretKey}|{timestamp}|{playerId}|{gameId}|{serial}|{currency}|{stake}|{count}
Success Response (200 OK)
{
"serial": "UNIQUE-SERIAL-001",
"internalId": "generated-internal-id",
"count": 10,
"used": 0,
"expires": "2026-12-31T23:59:59+00:00"
}
Error Response (400 Bad Request)
{
"serial": "UNIQUE-SERIAL-001",
"errorCode": {
"id": 901,
"msg": "Request validation failed."
}
}
List Free Plays
Endpoint
GET /s/bonus/freeplay/list?playerId={playerId}&gameId={gameId}¤cy={currency}
Description
Retrieves all active, non-expired free plays for a specific player, game, and currency.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
playerId
|
string | Yes | External player identifier |
gameId
|
string | Yes | Game ID |
currency
|
string | Yes | ISO 4217 currency code |
Signature Parameters
{partnerId}|{secretKey}|{timestamp}|{playerId}|{gameId}|{currency}
Success Response (200 OK)
{
"tickets": [
{
"serial": "UNIQUE-SERIAL-001",
"currency": "EUR",
"stake": 1.0,
"availableTickets": 5
},
{
"serial": "UNIQUE-SERIAL-002",
"currency": "EUR",
"stake": 2.5,
"availableTickets": 10
}
]
}
Error Response (400 Bad Request)
{
"errorCode": {
"id": 901,
"msg": "Request validation failed."
}
}
Revoke Free Play
Endpoint
POST /s/bonus/freeplay/revoke
Description
Revokes, or suspends, an active free play by serial number.
Request Body
{
"playerId": "player123",
"gameId": "1",
"serial": "UNIQUE-SERIAL-001"
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
playerId
|
string | Yes | External player identifier |
gameId
|
string | Yes | Game ID |
serial
|
string | Yes | Serial number to revoke |
Signature Parameters
{partnerId}|{secretKey}|{timestamp}|{playerId}|{gameId}|{serial}
Success Response (200 OK)
{
"serialRevoked": "UNIQUE-SERIAL-001"
}
Error Response (400 Bad Request)
{
"serial": "UNIQUE-SERIAL-001",
"errorCode": {
"id": 915,
"msg": "Free play not found."
}
}
Get Available Games
Endpoint
GET /s/bonus/freeplay/games
Description
Retrieves all games available for free play assignment for the partner, including betting limits and available stakes.
Query Parameters
None required. The partner is identified via headers.
Signature Parameters
{partnerId}|{secretKey}|{timestamp}
Success Response (200 OK)
{
"games": [
{
"id": 1,
"name": "Classic game",
"limits": {
"minBet": 0.10,
"maxBet": 100.00,
"maxWinPerBet": 5000.00
},
"stakes": []
},
{
"id": 50,
"name": "Slot game",
"limits": {
"minBet": 1.00,
"maxBet": 500.00,
"maxWinPerBet": 10000.00
},
"stakes": [1.0, 2.0, 5.0, 10.0, 25.0, 50.0]
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
games
|
array | List of available games |
games[].id
|
integer | Game ID |
games[].name
|
string | Game name |
games[].limits
|
object | Betting limits for the partner |
games[].limits.minBet
|
number | Minimum bet amount |
games[].limits.maxBet
|
number | Maximum bet amount |
games[].limits.maxWinPerBet
|
number | Maximum win per bet |
games[].stakes
|
array | Predefined stakes, slot games only |
Error Response (400 Bad Request)
{
"errorCode": {
"id": 902,
"msg": "Signature mismatch."
}
}
Complete Error Codes Reference
| Code | Message | Applicable Endpoints |
|---|---|---|
| 900 | No valid post data provided | assign, revoke |
| 901 | Request validation failed | all |
| 902 | Signature mismatch | all |
| 903 | Wrong headers | all |
| 910 | Partner not found | all |
| 911 | Game not found | assign, list, revoke |
| 912 | Currency invalid | assign, list |
| 914 | External game not found | assign (Slot) |
| 915 | Free play not found | revoke (Slot) |
| 916 | Free play not found | revoke (Classic) |
| 930 | Invalid expiration date format | assign |
| 932 | No handler found | assign, list, revoke |
| 941 | Communication error | assign (Slot) |
Request/Response Examples
Example 1: Assign Free Play (Classic Game)
Request:
POST /s/bonus/freeplay/assign
X-OPERATOR: PARTNER123
X-TIMESTAMP: 2026-03-12T10:30:00Z
X-SIGNATURE: aGFzaGVkX3NpZ25hdHVyZV9leGFtcGxl
Content-Type: application/json
{
"playerId": "player_ext_456",
"gameId": "1",
"serial": "FB-2026-001",
"currency": "EUR",
"stake": "5.00",
"count": 1,
"expires": "2026-12-31T23:59:59+00:00",
"minOddValue": 1.00,
"maxOddValue": 100.00
}
Success Response:
{
"serial": "FB-2026-001",
"internalId": "FB-2026-001",
"count": 1,
"used": 0,
"expires": "2026-12-31T23:59:59+00:00"
}
Example 2: Assign Free Play (Slot Game)
Request:
POST /s/bonus/freeplay/assign
X-OPERATOR: PARTNER123
X-TIMESTAMP: 2026-03-12T10:30:00Z
X-SIGNATURE: YW5vdGhlcl9oYXNoZWRfc2lnbmF0dXJl
Content-Type: application/json
{
"playerId": "player_ext_789",
"gameId": "50",
"serial": "FP-SLOT-2026-001",
"currency": "USD",
"stake": "10.00",
"count": 25,
"expires": "2026-12-31T23:59:59+00:00"
}
Success Response:
{
"serial": "FP-SLOT-2026-001",
"internalId": "SLOT-INTERNAL-12345",
"count": 25,
"used": 0,
"expires": "2026-12-31T23:59:59+00:00"
}
Example 3: List Free Plays
Request:
GET /s/bonus/freeplay/list?playerId=player_ext_456&gameId=1¤cy=EUR X-OPERATOR: PARTNER123 X-TIMESTAMP: 2026-03-12T11:00:00Z X-SIGNATURE: bGlzdF9zaWduYXR1cmVfZXhhbXBsZQ==
Success Response:
{
"tickets": [
{
"serial": "FB-2026-001",
"currency": "EUR",
"stake": 5.0,
"availableTickets": 1
},
{
"serial": "FB-2026-002",
"currency": "EUR",
"stake": 10.0,
"availableTickets": 1
}
]
}
Example 4: Revoke Free Play
Request:
POST /s/bonus/freeplay/revoke
X-OPERATOR: PARTNER123
X-TIMESTAMP: 2026-03-12T12:00:00Z
X-SIGNATURE: cmV2b2tlX3NpZ25hdHVyZV9leGFtcGxl
Content-Type: application/json
{
"playerId": "player_ext_456",
"gameId": "1",
"serial": "FB-2026-001"
}
Success Response:
{
"serialRevoked": "FB-2026-001"
}
Example 5: Get Available Games
Request:
GET /s/bonus/freeplay/games X-OPERATOR: PARTNER123 X-TIMESTAMP: 2026-03-12T13:00:00Z X-SIGNATURE: Z2FtZXNfc2lnbmF0dXJlX2V4YW1wbGU=
Success Response:
{
"games": [
{
"id": 1,
"name": "Bet on Poker",
"limits": {
"minBet": 0.5,
"maxBet": 200.0,
"maxWinPerBet": 10000.0
},
"stakes": []
},
{
"id": 50,
"name": "Baccarat",
"limits": {
"minBet": 1.0,
"maxBet": 500.0,
"maxWinPerBet": 25000.0
},
"stakes": [1.0, 2.0, 5.0, 10.0, 25.0, 50.0, 100.0]
}
]
}
Versioning
Public integration guide for partner developers. Your assigned version is configured by BetGames. Contact your integration manager to enable the API or request a version upgrade.
What “version” means
The Bonus Play API has three public contract versions: 1.0, 2.0, and 2.1.
- URLs do not change between versions.
- You do not send a version header or query parameter.
- BetGames assigns the active version to your operator account.
- The server applies the validation rules for that version automatically.
- If the API is not enabled for your account, requests return error
918—Bonus Play API is not enabled for this partner.
Quick comparison
| Feature | 1.0
|
2.0
|
2.1
|
|---|---|---|---|
| Status | Legacy | Current recommended | Strict / newest |
| Game types supported | Slot games only | Classic + slot games | Classic + slot games |
| Extra request fields | Allowed, ignored | Allowed, ignored | Rejected |
| Field type checking | Lenient | Lenient | Strict |
minOddValue / maxOddValue on assign
|
Not supported | Optional | Optional |
gameCategory in GET /s/bonus/freeplay/games response
|
Not included | Included | Included |
Recommendation for new integrations: implement against 2.1. Use 2.0 only if you need backward-compatible lenient validation during migration.
How the version affects your integration
All versions share the same base URL, endpoints, authentication headers (X-OPERATOR, X-TIMESTAMP, X-SIGNATURE), signature algorithm, and response formats, except where noted below.
Differences are in:
- which games you can use;
- which fields are accepted;
- how strictly requests are validated.
Version details
Version 1.0 — slots only (legacy)
Use this version if you only assign free play to slot games.
- Assign / list / revoke:
gameIdmust be a slot game ID. - Assign:
minOddValueandmaxOddValueare not part of the contract. - Validation: lenient — unknown JSON fields are allowed; numeric fields may be sent as strings, for example
"5". GET /s/bonus/freeplay/games: returns game list withoutgameCategory.
Version 2.0 — classic + slot games
Use this version if you need free play on classic BetGames games and slot games.
What is new compared with 1.0:
- Assign / list / revoke:
gameIdmay be a classic or slot game ID. - Assign: optional
minOddValueandmaxOddValue. Both must be sent together, andminOddValuemust be less than or equal tomaxOddValue. GET /s/bonus/freeplay/games: each game includesgameCategory:classic_gamesorslot_games.- Validation: still lenient — extra fields are allowed; types are not strictly enforced.
Version 2.1 — classic + slot games, strict validation
Same game coverage as 2.0, with stricter request validation. This is the best version for new integrations.
What is new compared with 2.0:
- Unknown fields are rejected. Do not send extra properties in JSON bodies or unknown query parameters on list.
- Strict field types are enforced.
GET /s/bonus/freeplay/games: same as2.0, includinggameCategory.
Version 2.1 field typing
| Field | Expected type | Notes |
|---|---|---|
playerId
|
string | |
gameId
|
string | Must be an allowed game ID |
serial
|
string | Assign / revoke |
currency
|
string | Case-insensitive; see Authentication & currency |
stake
|
positive decimal | Assign |
count
|
positive integer | Assign |
minOddValue, maxOddValue
|
positive decimal | Optional; both or neither |
Per-endpoint summary
| Endpoint | Method | Request payload | 1.0
|
2.0
|
2.1
|
|---|---|---|---|---|---|
| Assign | POST /s/bonus/freeplay/assign
|
JSON body | Slots only | Classic + slots; optional odds range | Classic + slots; strict types |
| Revoke | POST /s/bonus/freeplay/revoke
|
JSON body | Slots only | Classic + slots | Classic + slots; strict types |
| List | GET /s/bonus/freeplay/list
|
Query string only | Slots only | Classic + slots | Classic + slots; strict types |
| Games | GET /s/bonus/freeplay/games
|
Headers + signature only | No gameCategory
|
Includes gameCategory
|
Includes gameCategory
|
List endpoint note: parameters are passed as URL query parameters (playerId, gameId, currency), not in a request body.
Authentication & currency (all versions)
| Endpoint | Values included in signature |
|---|---|
| List | playerId, gameId, currency
|
| Assign | playerId, gameId, serial, currency, stake, count
|
| Revoke | playerId, gameId, serial
|
| Games | Signature over headers only — no request fields |
Currency:
- You may send
currencyin any case, for exampleusd,USD, orUsd. - Build the signature with the exact value you send in the request, using the same casing in the URL/body and signature payload.
- Responses and stored values use uppercase ISO codes, for example
USDorEUR.
Upgrading between versions
| From → To | Action required on your side |
|---|---|
1.0 → 2.0
|
Support classic game IDs; handle gameCategory in the games response; optionally use minOddValue / maxOddValue on assign.
|
2.0 → 2.1
|
Remove extra/unknown fields; ensure correct JSON types; ensure list uses only documented query parameters. |
1.0 → 2.1
|
Combine both steps above. |
You do not need to change URLs or authentication when BetGames upgrades your version. Test on staging after BetGames confirms the switch.
Which version am I on?
BetGames configures this per operator. To confirm:
- Ask your BetGames contact, or
- Infer from behavior on staging:
918→ API not enabled- Assign to a classic game ID succeeds →
2.0or2.1 - Assign to a classic game ID fails with game validation error → likely
1.0 - Unknown field in assign body fails →
2.1 - Unknown field in assign body is ignored →
2.0or1.0
FAQ
Do I put the version in the URL?
No. Endpoints are identical for all versions.
Will BetGames change my version without notice?
Version changes are coordinated with your integration team. You will be told when to adjust your client.
Is 1.0 deprecated?
It remains supported for existing slot-only integrations. New partners should use 2.1.
Why does list behave differently from assign?
List is a GET request: parameters go in the query string, not the body. Assign and revoke use a JSON body.
What error do I get if my version does not support a game?
Validation fails, typically with 901, if gameId is not allowed for your version, for example a classic game on 1.0.