B2B API Integration Guide
Welcome to the Win20X Developer Documentation. Our platform enables seamlessly embedding 100+ top-tier casino game suppliers (including Aviator, Slots, Table Games, and Live dealers) directly into your website via a unified B2B gateway.
This integration is executed in an A-Z flow: retrieving providers, fetching game lists, generating launch links, and processing transactional webhooks on your player ledger.
API Credentials & Authentication
All outbound API requests from your server to our gateway must connect over HTTPS to https://api.win20x.com and present B2B credentials in the request headers.
| Header Name | Description |
|---|---|
x-api-key |
Your B2B Client API Key (issued via your B2B Client Portal). |
x-api-secret |
Your B2B Client API Secret (issued via your B2B Client Portal). |
Note: API requests will be rejected unless the originating server IP address is whitelisted in your B2B dashboard.
1. Retrieve Game Providers
Fetch all active game suppliers integrated on the SaaS gateway.
Sample Response:
{
"success": true,
"message": "All games grouped by provider fetched successfully",
"games": [
"SPRIBE",
"EVOPLAY",
"PRAGMATIC",
"ODIN"
]
}
2. Retrieve Games List
Retrieve the complete game portfolio mapping of a specific supplier.
Query Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
provider |
string | Yes | E.g. SPRIBE or EVOPLAY |
Sample Response:
{
"success": true,
"message": "All games for EVOPLAY fetched successfully",
"games": [
{
"id": "75f81c56565d394503f544f3431ef370",
"name": "Aviator",
"provider_name": "SPRIBE",
"game_type": "crash"
}
]
}
3. Generate Game Session URL
Requests a secure session launcher link to frame or load the game for your player. When you call this, player balances are automatically synchronized with our transaction ledger.
JSON Body Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
username |
string | Yes | Your player's unique username or ID on your system. |
gameId |
string | Yes | The unique game code (from Step 2). |
money |
number | Yes | The player's current balance in BDT (৳) (Decimal format). |
platform |
number | Yes | 1 for Desktop, 2 for Mobile/Tablet. |
currency |
string | Yes | Must pass BDT. |
home_url |
string | Yes | The absolute redirect target URL when the player exits the game session. |
lang |
string | No | Language (defaults to en). |
Sample Response:
{
"success": true,
"msg": "SUCCESS",
"url": "https://api.win20x.com/lobby/launcher?session_token=p_1_user99&game=aviator"
}
4. Inbound Transaction Callbacks
During game play (placing bets, wins, and bonus updates), our system will send HTTP POST webhooks back to your registered Inbound Callback Webhook URL. Your backend must listen to these events, update the player balance on your system in real-time, and return a successful JSON confirmation.
POST Request Payload:
{
"bet_amount": 100.0000,
"win_amount": 250.0000,
"member_account": "p_1_user99",
"game_uid": "75f81c56565d394503f544f3431ef370",
"game_round": "round_unique_12345",
"currency_code": "BDT",
"api_key": "wjr4_api_key_xyz",
"serial_number": "txn_unique_serial_556"
}
Required Response Body (JSON, HTTP Status 200):
{
"success": true,
"message": "Callback processed successfully"
}
Callback Security & Webhook Rules
To avoid security vulnerabilities (such as double payout exploits or replay attacks), your system must strictly follow these rules:
- Validate the API Key: Check that the incoming
api_keyin the payload matches your own B2B API Key. - Player Username Masking: The incoming
member_accountwill contain the internal masked player token we generated (e.g.p_{clientId}_{username}). Map this back to your user. - Strict Idempotency Check: Log the unique transaction
serial_numberin your database. If you receive a webhook with aserial_numberthat is already marked as processed in your ledger, do not deduct or credit balances again. Simply respond with success200 OKimmediately. - Atomic Ledger Updates: Calculate:
New Balance = Current Balance - bet_amount + win_amountin a single database transaction.
Integration Code Snippets
<?php
// Inbound callback route (listen at your registered callback URL)
header('Content-Type: application/json');
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 1. Basic validation
if (!$data || !isset($data['serial_number']) || !isset($data['member_account'])) {
echo json_encode(['success' => false, 'message' => 'Malformed payload']);
exit;
}
$apiKey = $data['api_key'];
$memberAccount = $data['member_account'];
$betAmount = (float)$data['bet_amount'];
$winAmount = (float)$data['win_amount'];
$serialNumber = $data['serial_number'];
// 2. Validate API Key
$myApiKey = "YOUR_API_KEY"; // Set your API key here
if ($apiKey !== $myApiKey) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
// Connect to Database
$db = new PDO('mysql:host=localhost;dbname=casino', 'db_user', 'db_pass');
try {
$db->beginTransaction();
// 3. Idempotency Check
$stmt = $db->prepare("SELECT 1 FROM processed_txs WHERE serial_number = ? FOR UPDATE");
$stmt->execute([$serialNumber]);
if ($stmt->fetch()) {
$db->rollBack();
echo json_encode(['success' => true, 'message' => 'Duplicate transaction']);
exit;
}
// Extract player ID from secure token (p_{clientId}_{username})
$parts = explode('_', $memberAccount);
$playerUsername = end($parts);
// Lock player balance row
$userStmt = $db->prepare("SELECT balance FROM users WHERE username = ? FOR UPDATE");
$userStmt->execute([$playerUsername]);
$user = $userStmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
$db->rollBack();
echo json_encode(['success' => false, 'message' => 'Player not found']);
exit;
}
$currentBalance = (float)$user['balance'];
$newBalance = $currentBalance - $betAmount + $winAmount;
if ($newBalance < 0) {
$db->rollBack();
echo json_encode(['success' => false, 'message' => 'Insufficient funds']);
exit;
}
// Update player balance
$updateStmt = $db->prepare("UPDATE users SET balance = ? WHERE username = ?");
$updateStmt->execute([$newBalance, $playerUsername]);
// Record serial number to prevent replay attacks
$logStmt = $db->prepare("INSERT INTO processed_txs (serial_number, amount) VALUES (?, ?)");
$logStmt->execute([$serialNumber, $winAmount - $betAmount]);
$db->commit();
echo json_encode(['success' => true, 'message' => 'Callback processed successfully']);
} catch (Exception $e) {
$db->rollBack();
echo json_encode(['success' => false, 'message' => 'Database transaction failed: ' . $e->getMessage()]);
}