Seamless Wallet Endpoints: getbalance & balance_adj
Essential credentials required to integrate: API Encryption Key, Operator ID
For the Seamless Wallet functionality to work, the RGS-CWS will need to send HTTP POST requests to two URLs provided by your team:
getbalance: to retrieve player wallet balance.balance_adj: to update player wallet (bet, win, cancelbet, cancelwin).
These endpoints must follow our security and response guidelines. Be sure to read Security โ Trusting Our Data for hash validation setup and other guidelines.
IMPORTANT: Our games will send data to your endpoints, only when the game is opened in โreal modeโ. โfun modeโ will not send any data to your endpoints.
NOTE: It is also important for your code to respond in a short amount of time and avoid timing out. We consider a timed out transaction to be a transaction with a response time >=5 seconds. After this time, the transaction is retried once, right away. If no success, it will be put in a queue and it will be cancelled (cancel request being sent once every 5 minutes - this interval increases and becomes less frequent)
๐ณ getbalance Endpoint
Used by RGS-CWS to request the current balance of a player from your platform.
RGS-CWS will send a JSON string in a POST request. You must decode and parse it. The structure is as follows:
๐ Sample JSON Request from RGS-CWS to your server - getbalance:
POST /getbalance.php
{
"command":"getbalance",
"userid":"224",
"login":"u241_8841",
"timestamp":"2025-07-02 14:10:00"
}๐ฅ Input Parameters (coming from RGS-CWS) - getbalance:
Parameter | Always Present | Description | DataType |
| โ | Must be | string |
| โ | Unique RGS-CWS user ID. You can ignore | string |
| โ | Username from your system, that you originally passed when registering the user or generating the game play token โ but it will be prefixed. You must replace โu241_โ with โโ(nothing) , assuming 241 is your operator id. Player username (may include currency suffix in format: username_CURRENCY, e.g., "john_USD". Remove the suffix to get the original username) | string |
| โ | Expiry timestamp (max 15 minutes ahead) | string |
| โ | Currency code (e.g. | string |
| โ | PHP Session ID | string |
| โ | Unique ID of current Request | string |
| โ | This has always the value โgetbalanceโ for this endpoint | string |
| โ | This represents the value of the custom_data string that you initialized when you generated the game token. If you did not set any value, it will be empty. | string |
| โ | HMAC-SHA256 signature ; key=your This is obtained by hashing these variables, in this exact order:
Sample hashing code: | string |
IMPORTANT: The
loginwill always contain a prefix.
For production the prefix is โu241_โ, where 241 is your operator id. This is different for every operator.
For staging the prefix is โstg_u241_โ, where 241 is your operator id. This is different for every operator.
You must trim this prefix.
IMPORTANT: Theloginparameter may also contain a currency suffix in the following format:username_CURRENCY
Examples:
-john_USD(user "john" playing with USD)
-player123_EUR(user "player123" playing with EUR)
-testuser_BTC(user "testuser" playing with BTC)Please remove the currency suffix from the end of the login string. You can find a code snippet below on how to do it properly.
Warning: When writing your code, make sure you do the trimming only at the end to avoid scenarios where the currency code appears in the username itself. For example, if the currency isCOINSand the username isjoe_coinstar, you should NOT accidentally remove_coinsfrom the middle of the username.
$operatorid = 241;
//PRODUCTION
$login = str_replace('u'.$operatorid.'_','',$login)));
//STAGING
if ($request['environment']=='staging'){
$login = str_replace('stg_u'.$operatorid.'_','',$login)));
}
//REMOVE CURRENCY SUFFIX (only at the end)
$suffix = '_'.strtoupper($currency);
if (substr($login, -strlen($suffix)) === $suffix) {
$login = substr($login, 0, -strlen($suffix));
}
๐ค Output Response Format (Expected from your server) - getbalance:
{
"status": "1",
"balance": "2221212.44"
}
๐ธ balance_adj Endpoint
Used by RGS-CWS to notify your system about real-time wallet changes like bets, wins, cancels.
RGS-CWS will send a JSON string in a POST request. You must decode and parse it. The structure is as follows:
๐ Sample JSON Request from RGS-CWS to your server - balance_adj
POST /balance_adj.php
{
"command": "balance_adj",
"amount": "-25.0000",//4 decimals precision, sent as string, not float
"userid": "1441",
"login": "u241_166273",
"type": "bet",
"timestamp": "2025-07-02 14:00:00",
"gpid": "100",
"uniqid": "1ee2a1a9c481f330cdb5f701d9c78bef",
"gameid": "6857",
"internal_session_id": "abc123",
"gpid_status": "nt",
"currency": "USD",
"subtype": "gamble",
"is_jackpot_win": "1",
"hashed_result": "..."
}
๐ฅ Input Parameters (coming from RGS-CWS) - balance_adj:
Parameter | Always present | Description | Data Type |
| โ | Must be | string |
| โ | Amount to adjust. Negative = bet, Positive = win. 4 decimal max | string |
| โ | RGS-CWS internal user ID | string |
| โ | Username from your system, that you originally passed when registering the user or generating the game play token โ but it will be prefixed. You must replace โu241_โ with โโ(nothing) , assuming 241 is your operator id. Player username (may include currency suffix in format: username_CURRENCY, e.g., "john_USD". Remove the suffix to get the original username) | string |
| โ | One of: | string |
| โ | Transaction expiry time (15 min ahead max) | string |
| โ | Game play ID (can be repeated across related transactions like freespins) | string |
| โ | Game round status: | string |
| โ | Game ID, e.g. | string |
| โ | Session identifier from RGS-CWS system. It has no specific purpose. | string |
| โ | Unique transaction ID. Use this to ensure idempotency | string |
| โ | Currency code (e.g. | string |
| โ | Optional. E.g. | string |
| โ | If present and set to | string |
| โ | HMAC-SHA256 signature ; key=your This is obtained by hashing these variables, in this exact order:
Sample PHP hashing code: | string |
๐ค Output Response Format (Expected from your server) - balance_adj:
Your endpoints must return a valid JSON response with the following fields:
Parameter | Required | Description | Type |
| โ |
| string |
| โ | New user balance (as a string with decimals). If no update was made, please return the current balance value. | string |
| โ | Unique transaction ID from your system. Can be a number or alphanumeric. | string |
| โ | Message shown to the player if status is | string |
๐ด Important: Returning
"status": "-1" or "status": "0"means the transaction is permanently rejected and will not be retried.
โ Example for success
{
"status": "1",
"balance": "22221212.44",
"txid": "TX3890021"
}
โ Example for failure
{
"status": "-1",
"balance": "22221212.44",
"errormsg": "Insufficient Balance"
} โ Best Practices
Remove prefixes and suffixes from the username
Always validate the hashed_result signature
Always verify if the user has sufficient funds in his wallet before applying balance adjustments. EG: if (amount<0 && wallet_balance+amount>=0) only then process it and make sure to update your local balance right away. If you use SQL, you can do conditional query and see number of affected rows after your query, to determine if the balance was updated or not
UPDATE users SET balance=balance+amount WHERE user=โmyusernameโ AND balance>=amount.Now count the number of affected rows (must be 1).Log all transactions, even failed ones, for auditability.
Optimize your setup by NOT updating the balance when the amount is 0$, but store the transactions for idempotency and gameplay progress tracking
Always validate that incoming transactions are not duplicated using the
uniqidfield. If you processed a transaction in the past, do not process it again.Use a timestamp window (e.g. 15 minutes) to reject expired requests.
When receiving a
cancelbetorcancelwin, search and reverse the matching original transaction or rely on the amount value that we send to apply to the player balance.
EG: a bet request like this{"type":"bet","amount":"-25","txid":"891h591gajsoeg"}will have an equivalent cancelbet such as this{"type":"cancelbet","amount":"25","txid":"cancel_891h591gajsoeg"}Always send amounts as numeric strings with 2 to 4 decimal places (e.g.,
"25.00","0.1234").Do not reject duplicate transactions silently โ always reply with
status: 1if already handled.
๐ Verifying Signature
If hashed_result is included, verify it using your API secret key. Read more here.
//Sample code to validate the hashed string in the balance_adj endpoint
//Sample code to validate the hashed string in the balance_adj endpoint
$calculated_hash = hash_hmac('sha256', json_encode(array(
$data['command'],
$data['timestamp'],
$data['login'],
$data['internal_session_id'],
$data['uniqid'],
$data['type'],
$data['userid'],
$data['custom_data'],
$data['amount'], //in getbalance this is not sent so please adjust accordingly
$data['gameid'], //in getbalance this is not sent so please adjust accordingly
$data['gpid'], //in getbalance this is not sent so please adjust accordingly
$data['currency'],
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $api_encryption_key);
$sent_hash = $data['hashed_result'] ?? '';
if (!hash_equals($calculated_hash, $sent_hash)) { // โ Changed from $hashed_result to $sent_hash
// Invalid signature - reject the request
http_response_code(403);
echo json_encode(['status' => '-1', 'balance' => '0.00', 'errormsg' => 'Invalid signature']);
exit;
}
// Valid - continue processingReject request if computed hash does not match
hashed_resultThis improves trust between RGS-CWS and your system
๐ซ Insufficient Funds
On bet requests, check player's wallet before processing.
If balance is not enough:
Return
status: "-1"Include a proper
errormsgso the game client can display it
{ "status": "-1", "balance": "4.00", "errormsg": "Insufficient balance" }Important: Log rejected transactions for idempotency check
๐ Idempotency
Each transaction comes with a unique
uniqid.You must check if the
uniqidwas already processed by your system (store each uniqid in a database table and perform search queries to see if you already have it processed):If yes, respond with
status: "1"and the last known balance.If no, process the transaction normally and store the
uniqid. Respond adequately (status:"1")
Required to avoid double processing of bets or wins in case of retries.
// Response that your server should return on Duplicate transaction ID
{ "status": "1", "balance": "123.45" }โ๏ธ Cancel Transactions
RGS-CWS may send cancelbet or cancelwin operations if a transaction expires or is rolled back. You can read more about this in the โHandling Timeoutsโ documentation section.
This feature is available only on-demand.
Field | Value | Notes |
|
| Indicates the reversal of a previous bet or win |
|
| Strip |
Best practice: treat
cancel_123456abcdefas a rollback for the transaction withuniqid = 123456abcdef
๐ Retry Policy
Player experience: A win that cannot be confirmed in real time does not block the player โ the game session continues and the win is delivered later by the retry process. A bet requires a confirmed debit from your endpoints: an unconfirmed bet ends the round (reversed via cancelbet if needed).
If your system does not respond within 5 seconds or returns a malformed response:
The same win request will be retried every 5 minutes
Bet requests will be cancelled and passed as
type=cancelbetRetries will continue until a valid JSON response with
status: "1"is received
Common reasons for retry: Timeout, No response, Missing/invalid status field in JSON
Common reasons for retry:
Timeout
No response
Missing/invalid
statusfield in JSON
You must ensure that duplicate handling logic is applied via
uniqidIn the future the retry mechanism may suffer changes and the time interval for repeating will grow exponentially (5 min for #1 attempt, 10 min for #2 attempt, 30, 60, 120, 300, 600, 600, 600, but never stop). This feature is available only on-demand.
๐ ๏ธ You can optionally set up a cronjob on your server to execute every 5 minutes and to fetch and process missed wins or bets by polling endpoints described in E27/E28 of the original documentation. You can read more about this in the Handling Timeouts documentation section.