Change Player Balance
This API changes a player's balance. It is provided by the merchant (operator) and called by the game platform.
The API is called once for each operation, such as placing a bet, canceling a bet, issuing a payout, or ending a game.
The value of the changeType field differs for each operation.
Request URL
POST {API_URL_ROOT}/player/changeBalance
Note: This URL can be configured in the merchant backend, but the request and response parameters must meet the requirements below.
Request Parameters
Header
| Field | Required | Type | Description |
|---|---|---|---|
| sign | YES | string | Signature calculated using the Signature Algorithm. |
| timestamp | YES | int | Timestamp in seconds since January 1, 1970, e.g. 1741837297. |
| Accept-Language | YES | string | Accepted language code. See the Language List, e.g. zh or en. This is used to return localized error messages. |
| Content-Type | YES | string | application/json; charset=utf-8 |
BODY
| Field | Required | Type | Description |
|---|---|---|---|
| recordId | YES | string | Game record ID that uniquely identifies each game played by a player. |
| txId | YES | string | Transaction ID that uniquely identifies each request. |
| tenantId | YES | int | Merchant ID: a unique integer assigned by the platform. |
| userId | YES | string | Merchant's player ID that uniquely identifies each player. |
| gameId | YES | int | Game ID. |
| changeType | YES | int | Balance change type. See the changeType value list below. |
| betType | YES | int | Bet type. See the betType value list below. |
| betAmount | YES | double | Bet amount. |
| bonus | YES | double | Payout amount. |
| multiple | NO | double | Payout multiplier. This value may sometimes differ slightly from bonus / betAmount. For example, this can happen when a preset multiplier is used for a payout and the payout amount reaches the maximum payout limit. |
| roundId | NO | string | Round ID. Primarily used in multiplayer games to uniquely identify each game round. |
| area | NO | int | Area ID. The default is 0. Some games support bets in different areas, and this field distinguishes those areas. |
| currency | NO | string | Currency code. |
| isCompleted | NO | bool | Whether the game round is complete. This field is required for a payout. For the final payout, set this field to true to avoid an additional end-game request (changeType=4). |
| isRetry | NO | bool | Whether this request is a retry. If a request times out or does not return a valid result, up to six retries may be triggered until a successful response is received. This value is true for retry requests. |
| parentId | NO | string | Parent record ID. A slot game may trigger free spins. If the current record is for a free spin, parentId is the record ID of the original bet. In this case, betType=3 and betAmount=0 identify the free spin. |
The values of the fields vary according to changeType. The following six scenarios are supported:
Bet and payout:
changeType=0betAmounthas a value.- A
bonusvalue greater than0indicates a payout;bonus=0indicates no payout. multipleis the payout multiplier. If it is provided, the system uses it; otherwise, the system calculates it usingbonus / betAmount.isCompleted=trueends the bet immediately.
Normal bet:
changeType=1betAmounthas a value andbonus=0.
Cancel bet:
changeType=2betAmountis the amount of the original bet.
Payout:
changeType=3betAmount=0andbonushas a value.- Some games may issue multiple payout calls.
multipleis the payout multiplier. If it is provided, the system uses it; otherwise, the system calculates it usingbonus / betAmount.- For the final payout, set
isCompleted=trueto indicate that the game round has ended. This has the same effect as making another call withchangeType=4.
End game:
changeType=4betAmount=0andbonus=0.
Free spins triggered in a slot game:
changeType=0betType=3identifies the bet as a free spin.parentIdcontains the record ID of the original bet that triggered the free spin.- A free-spin feature may issue multiple payouts, and each payout has a different
recordId.
Example
Six Scenarios
// Bet and payout scenario:
{
"recordId": "682ed6edce1c812d736c4876",
"txId": "682ed6edce1c812d736c4877",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 0,
"betType": 0,
"betAmount": 100.00,
"bonus": 30,
"multiple": 0.30,
"roundId": "12353",
"area": 0,
"currency": "BRL",
"details": null,
"isCompleted": true
}
// Normal bet scenario:
{
"recordId": "682ed6edce1c812d736c4876",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 1,
"betType": 1,
"betAmount": 100.00,
"bonus": 0,
"multiple": 0,
"roundId": "12353",
"area": 0,
"currency": "BRL",
"details": null,
"isCompleted": false
}
// Cancel bet scenario:
{
"recordId": "682ed6edce1c812d736c4876",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 2,
"betType": 1,
"betAmount": 100.00,
"bonus": 0,
"multiple": 0,
"roundId": "12353",
"area": 0,
"currency": "BRL",
"details": null,
"isCompleted": false
}
// Payout scenario:
{
"recordId": "682ed6edce1c812d736c4876",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 3,
"betType": 1,
"betAmount": 0,
"bonus": 50.00,
"currency": "BRL",
"details": null,
"isCompleted": true
}
// End-game scenario:
{
"recordId": "682ed6edce1c812d736c4876",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 4,
"betType": 1,
"betAmount": 0,
"bonus": 0,
"multiple": 0,
"roundId": "12353",
"area": 0,
"currency": "BRL",
"details": null,
"isCompleted": true
}
// Slot-game free-spin scenario:
{
"recordId": "682ed6edce1c812d73ac2899",
"tenantId": 2317,
"userId": "t20339",
"gameId": 2001,
"changeType": 0,
"betType": 3,
"betAmount": 0,
"bonus": 0,
"multiple": 0,
"roundId": "12353",
"area": 0,
"currency": "BRL",
"details": null,
"isCompleted": true,
"parentId": "682ed6edce1c812d736c4876"
}
Response Parameters
| Field | Required | Type | Description |
|---|---|---|---|
| tenantId | YES | int | Merchant ID: a unique integer assigned by the platform. |
| userId | YES | string | Merchant's user ID that uniquely identifies each player. |
| balance | NO | double | Player balance. Regardless of whether the deduction succeeds, the current account balance must be returned correctly so that the account balance can be updated. |
| currency | NO | string | Game currency code. |
Important: Regardless of whether isSuccess is true or false, the current account balance must be returned correctly. The system updates the current account balance using the balance value. If the account status is abnormal and the player cannot play, balance must be 0.
Merchants may encounter various unforeseen errors while processing a request. To keep the platform's processing status consistent with the merchant's status, several error codes have been predefined. If a similar error occurs, return the corresponding error code below:
| isSuccess | code | message | data | Scenario Description |
|---|---|---|---|---|
| true | 0 | null | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL"} | The request was processed successfully and returned normally. |
| false | 1 | For example: Invalid request or parameter validation error. The content can be customized. | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL"} | Request parameter validation or the merchant's own business validation failed. Return the user's balance if it is available. The message can be customized according to the merchant's business requirements; there is no fixed message. |
| false | 2 | Failed to retrieve user balance | None | The player's balance could not be retrieved or returned. |
| false | 3 | Insufficient player balance | {"tenantId":1,"userId":"276682","balance":0.5,"currency":"BRL"} | The player's balance is less than the bet amount. |
| false | 4 | Failed to update balance | {"tenantId":1,"userId":"276682","balance":0.5,"currency":"BRL"} | The balance update failed. The returned balance is the balance after the last successful update. |
| false | 5 | Order already exists or duplicate bet | {"tenantId":1,"userId":"276682","balance":0.5,"currency":"BRL"} | The recordId already exists and changeType=0 or changeType=1 was called again. The same recordId can be used to place a bet only once; this is an idempotency check. |
| false | 6 | Order does not exist | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL"} | No order with the specified recordId was found when canceling a bet, issuing a payout, or ending a game. |
| false | 7 | Order already canceled; duplicate cancellation | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL"} | The order has already been canceled. This error is returned if it is canceled again. |
| false | 8 | Order already settled; duplicate payout or game end | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL"} | The order has already received a payout or ended. This error is returned if payout, end game, or the combined changeType=0 mode is called again. |
| false | 9 | Abnormal order status | {"tenantId":1,"userId":"276682","balance":100000,"currency":"BRL", changeType: 4} | This error is returned when attempting to issue a payout for or end an order that has already been canceled, or when attempting to cancel an order that has already received a payout or ended. The order's current changeType must also be returned. This can occur when a call to the merchant API times out or returns an error, so the platform cannot determine the order's current status. |
| false | 500 | System error | None | Internal server error. Merchants are advised to handle exceptions uniformly at the outermost level of the entire order-processing flow. |
The platform handles all scenarios listed above with codes from 0 through 9. Other scenarios are not handled.
Example
{
"isSuccess": true,
"code": 0,
"data": {
"tenantId": 1,
"userId": "t1_276682",
"balance": 100000,
"currency": "BRL"
}
}
// Insufficient balance scenario:
{
"isSuccess": false,
"code": xxx, // Merchant's insufficient-balance error code, e.g. 2012
"message": "Insufficient balance; bet failed",
"data": {
"tenantId": 1,
"userId": "t1_276682",
"balance": 1.0, // Current balance
"currency": "BRL"
}
}
// Player disabled scenario:
{
"isSuccess": false,
"code": xxx, // Merchant's abnormal-status error code, e.g. 2013
"message": "Player disabled; bet failed",
"data": {
"tenantId": 1,
"userId": "t1_276682",
"balance": 0.0, // Must be 0
"currency": "BRL"
}
}
betType Value List
| Value | Description |
|---|---|
| 1 | Normal bet |
| 2 | Cascade |
| 3 | Free spin |
| 4 | Respin |
changeType Value List
| Value | Description |
|---|---|
| 0 | Bet and payout |
| 1 | Normal bet |
| 2 | Cancel bet |
| 3 | Payout |
| 4 | End game |
Game Flow Examples
For scenarios that do not combine a bet and payout into a single request, the following flows may occur:
Normal bet and payout
Game bet -> Game payout (
isCompleted=true): the correspondingchangeTypevalues are1 -> 3. The player places a bet, wins, and the result is settled; the game round then ends. This flow applies to most games. SettingisCompleted=truefor the final payout is recommended because it avoids one additional API call.Game bet -> Game payout -> Game round ends: the corresponding
changeTypevalues are1 -> 3 -> 4. The player places a bet, wins, and the result is settled; the game round then ends. This flow also applies to most games.Cancel bet
Game bet -> Cancel bet: the corresponding
changeTypevalues are1 -> 2. The player places a bet and voluntarily cancels it before the round starts. This generally applies to multiplayer games and mini-games. TherecordIdof the cancellation must be the same as therecordIdof the original bet.No payout
Game bet -> No win -> Game round ends: the corresponding
changeTypevalues are1 -> 4. The player places a bet but does not win the round, and the end of the round is then confirmed.Multiple payouts for one bet
This generally applies to cascading-reel slot games, slot games that enter a special feature, and lottery games. The player places one bet and wins multiple times during the round before it ends.
Game bet -> Game payout -> Game payout -> Game payout -> ... -> Game payout (
isCompleted=true): the correspondingchangeTypevalues are1 -> 3 -> 3 -> ... -> 3. SettingisCompleted=truefor the final payout is recommended because it avoids one additional API call.Game bet -> Game payout -> Game payout -> Game payout -> ... -> Game round ends: the corresponding
changeTypevalues are1 -> 3 -> 3 -> ... -> 4.