Wallet Callbacks
When a player launches a game or places a bet, the RGS calls your backend to authenticate the player, debit, or credit the player's balance. You must implement these five endpoints at the callback URL registered during onboarding.
All callbacks are POST requests with a JSON body, signed with HMAC-SHA256 via X-Timestamp and X-HMAC-SHA256 headers. See Authentication for verification details.
Currencies & Amounts
Amounts in all callbacks are represented as decimal strings (e.g., "1.50") to avoid floating-point precision issues. Use GET /operator/currencies to fetch the current list of supported currency codes.
RMB is accepted as an alias for CNY. If you need a currency not listed, contact us during onboarding.
Authenticate
POST /callback/authenticate — Verify the player and return their balance when a session is launched.
The RGS calls this endpoint during POST /operator/launch to confirm that the player exists and is allowed to play.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Unique identifier for this request |
playerId |
string | Yes | The player ID provided in the launch request |
currency |
string | Yes | Currency code for the session (e.g., "USD") |
gameCode |
string | Yes | Game code being launched (e.g., "dice-alpha") |
{
"requestId": "unique-request-id",
"playerId": "player-1",
"currency": "USD",
"gameCode": "dice-alpha"
}
Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Echo back the requestId from the request |
status |
string | Yes | "OK" on success, or an error code |
balance |
string | Yes (if OK) | Player's current balance as a decimal string (e.g., "100.00") |
accountCurrency |
string | No | Player's wallet currency — must match the request currency if provided |
name |
string | No | Player's display name |
countryCode |
string | No | Player's country (ISO 3166-1 alpha-2) |
languageCode |
string | No | Player's language preference (ISO 639-1) |
birthDate |
string | No | Player's date of birth (YYYY-MM-DD) |
registrationDate |
string | No | When the player registered (YYYY-MM-DD) |
address |
string | No | Player's address |
{
"requestId": "unique-request-id",
"status": "OK",
"balance": "100.00",
"accountCurrency": "USD",
"name": "John Doe",
"countryCode": "US",
"languageCode": "en",
"birthDate": "1990-01-01",
"registrationDate": "2024-01-15",
"address": "123 Main St"
}
If accountCurrency is provided, it must match the currency sent in the request. A mismatch will cause the launch to fail.
Debit
POST /callback/debit — Deduct the bet amount from the player's balance.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Unique identifier for this request |
playerId |
string | Yes | The player placing the bet |
transactionId |
string | Yes | Unique transaction ID — use as idempotency key |
roundId |
string | Yes | The game round this debit belongs to |
gameCode |
string | Yes | Game code (e.g., "dice-alpha") |
amount |
string | Yes | Bet amount as a decimal string (e.g., "1.50") |
metadata |
string | No | JSON string with extra transaction details |
{
"requestId": "unique-request-id",
"playerId": "player-1",
"transactionId": "unique-transaction-id",
"roundId": "round-uuid",
"gameCode": "dice-alpha",
"amount": "1.50",
"metadata": "{}"
}
Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Echo back the requestId from the request |
status |
string | Yes | "OK" on success, or an error code |
balance |
string | Yes (if OK) | Player's balance after the debit |
customUserError |
string | No | Message displayed to the player when the debit is rejected |
{
"requestId": "unique-request-id",
"status": "OK",
"balance": "98.50"
}
Credit
POST /callback/credit — Credit the player's balance with winnings.
The RGS always sends a credit callback, even when the player loses — the amount will be "0". A round is always closed by either a credit or a rollback, never by a debit alone. Check roundClosed to determine if the round has ended.
A credit with amount: "0" and roundClosed: true signals the round ended with no payout. Always respond with OK and the current balance.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Unique identifier for this request |
playerId |
string | Yes | The player receiving the credit |
transactionId |
string | Yes | Unique transaction ID — use as idempotency key |
roundId |
string | Yes | The game round this credit belongs to |
roundClosed |
boolean | Yes | true if this credit closes the round |
gameId |
string | Yes | Game code (e.g., "dice-alpha") |
amount |
string | Yes | Payout amount as a decimal string — "0" for losses |
metadata |
string | No | JSON string with extra transaction details |
{
"requestId": "unique-request-id",
"playerId": "player-1",
"transactionId": "unique-transaction-id",
"roundId": "round-uuid",
"roundClosed": true,
"gameId": "dice-alpha",
"amount": "3.00",
"metadata": "{}"
}
Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Echo back the requestId from the request |
status |
string | Yes | "OK" on success, or an error code |
balance |
string | Yes (if OK) | Player's balance after the credit |
{
"requestId": "unique-request-id",
"status": "OK",
"balance": "101.50"
}
sessionToken is not included in credit callbacks — payouts must succeed even after session expiry.
Balance
POST /callback/balance — Return the player's current balance (e.g., when loading the game UI).
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Unique identifier for this request |
playerId |
string | Yes | The player whose balance to return |
{
"requestId": "unique-request-id",
"playerId": "player-1"
}
Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Echo back the requestId from the request |
status |
string | Yes | "OK" on success, or an error code |
balance |
string | Yes (if OK) | Player's current balance |
{
"requestId": "unique-request-id",
"status": "OK",
"balance": "100.00"
}
Rollback
POST /callback/rollback — Reverse a previously placed bet. The RGS sends this when a debit callback fails (500 response, timeout, etc.) to ensure the player doesn't lose money if the debit was applied on your side. The reverseTransactionId identifies which debit transaction to reverse.
Your server must handle rollbacks that arrive before the corresponding debit — or for debits your server never acknowledged. If a debit call times out from the RGS side, the RGS may issue a rollback even though your server never confirmed the debit. Treat a rollback for an unknown reverseTransactionId as successful (return OK) since the original debit was never applied.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Unique identifier for this request |
playerId |
string | Yes | The player whose bet is being reversed |
transactionId |
string | Yes | Unique transaction ID for this rollback — use as idempotency key |
reverseTransactionId |
string | Yes | The transactionId of the original debit being reversed |
roundId |
string | Yes | The game round this rollback belongs to |
roundClosed |
boolean | Yes | true if this rollback closes the round |
gameId |
string | Yes | Game code (e.g., "dice-alpha") |
metadata |
string | No | JSON string with extra transaction details |
{
"requestId": "unique-request-id",
"playerId": "player-1",
"transactionId": "rollback-transaction-id",
"reverseTransactionId": "original-bet-transaction-id",
"roundId": "round-uuid",
"roundClosed": true,
"gameId": "dice-alpha",
"metadata": "{}"
}
Response Fields
| Field | Type | Required | Description |
|---|---|---|---|
requestId |
string | Yes | Echo back the requestId from the request |
status |
string | Yes | "OK" on success, or an error code |
balance |
string | Yes (if OK) | Player's balance after the rollback |
{
"requestId": "unique-request-id",
"status": "OK",
"balance": "100.00"
}
sessionToken is not included in rollback callbacks — reversals must succeed even after session expiry.
Response Status Codes
All callback responses must include a status field. Return "OK" on success, or one of these error codes:
| Status | Meaning |
|---|---|
OK |
Success |
ERROR_NOT_ENOUGH_MONEY |
Insufficient funds to place the bet |
ERROR_PLAYER_DISABLED |
Player account is locked or disabled |
ERROR_INVALID_SESSION |
Session token is unknown |
ERROR_SESSION_EXPIRED |
Session has expired |
ERROR_INVALID_GAME |
Game is unknown or disabled |
ERROR_WRONG_CURRENCY |
Currency mismatch with player's wallet |
ERROR_DUPLICATE_TRANSACTION |
transactionId already processed with different parameters |
ERROR_TRANSACTION_DOES_NOT_EXIST |
Rollback target bet was never processed (treat as success) |
ERROR_INVALID_SIGNATURE |
HMAC verification failed |
ERROR_WRONG_SYNTAX |
Malformed request |
ERROR_UNKNOWN |
Any other error |
Idempotency
Every /callback/debit, /callback/credit, and /callback/rollback request includes a unique transactionId. Your server should use this as an idempotency key — if you receive a request with a transactionId you've already processed, return the same successful response without applying the transaction again.
The RGS retries callbacks on transient failures (timeouts, 5xx responses). Each retry sends the same transactionId, so deduplication ensures transactions are only applied once.
Currently all games produce one debit and one credit per round. Future games may produce additional debit/credit pairs within a single round, so your callback implementation should support multiple transactions per roundId.