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

command

โœ…

Must be "getbalance"

string

userid

โœ…

Unique RGS-CWS user ID. You can ignore

string

login

โœ…

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.
In staging, you must replace โ€˜stg_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

timestamp

โœ…

Expiry timestamp (max 15 minutes ahead)

string

currency

โœ…

Currency code (e.g. USD, GC)

string

internal_session_id

โœ…

PHP Session ID

string

uniqid

โœ…

Unique ID of current Request

string

type

โœ…

This has always the value โ€œgetbalanceโ€ for this endpoint

string

custom_data

โœ…

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

hashed_result

โœ…

HMAC-SHA256 signature ; key=your api_encryption_key

This is obtained by hashing these variables, in this exact order:

command, timestamp, login, internal_session_id, uniqid, type, userid, custom_data, currency

Sample hashing code:

hash_hmac('sha256', json_encode(array(
$data['command'], 
$data['timestamp'], 
$data['login'],//original login, as we send it 
$data['internal_session_id'], $data['uniqid'], 
$data['type'], 
$data['userid'], 
$data['custom_data'],
$data['currency']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $api_encryption_key);

string


IMPORTANT: The login will 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: The login parameter 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 is COINS and the username is joe_coinstar, you should NOT accidentally remove _coins from 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

command

โœ…

Must be "balance_adj"

string

amount

โœ…

Amount to adjust. Negative = bet, Positive = win. 4 decimal max

string

userid

โœ…

RGS-CWS internal user ID

string

login

โœ…

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.
In staging, you must replace โ€˜stg_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

type

โœ…

One of: bet, win, cancelbet, cancelwin

string

timestamp

โœ…

Transaction expiry time (15 min ahead max)

string

gpid

โœ…

Game play ID (can be repeated across related transactions like freespins)

string

gpid_status

โœ…

Game round status: nt (incomplete), ok (completed)

string

gameid

โœ…

Game ID, e.g. 5203

string

internal_session_id

โœ…

Session identifier from RGS-CWS system. It has no specific purpose.

string

uniqid

โœ…

Unique transaction ID. Use this to ensure idempotency

string

currency

โœ…

Currency code (e.g. USD, EUR)

string

subtype

โŒ

Optional. E.g. gamble

string

is_jackpot_win

โŒ

If present and set to "1", the win was from a jackpot

string

hashed_result

โœ…

HMAC-SHA256 signature ; key=your api_encryption_key

This is obtained by hashing these variables, in this exact order:

command, timestamp, login, internal_session_id, uniqid, type, userid, custom_data, amount, gameid, gpid, currency

Sample PHP hashing code:

hash_hmac('sha256', json_encode(array(
$data['command'], 
$data['timestamp'], 
$data['login'],//original login, as we send it  
$data['internal_session_id'], $data['uniqid'], 
$data['type'], 
$data['userid'], 
$data['custom_data'], 
$data['amount'],
$data['gameid'],
$data['gpid'],
$data['currency']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $api_encryption_key);

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

status

โœ…

"1" = success (accepted); "-1" or "0" = rejected (permanent โ€” never retried; 0 is the legacy rejection value, still honored). Any other value, or no response within the timeout, is treated as undelivered and retried until you return a definitive 1, 0 or -1

string

balance

โœ…

New user balance (as a string with decimals). If no update was made, please return the current balance value.

string

txid

โœ…

Unique transaction ID from your system. Can be a number or alphanumeric.

string

errormsg

โŒ

Message shown to the player if status is -1 or 0.

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 uniqid field. 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 cancelbet or cancelwin, 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: 1 if 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 processing
  • Reject request if computed hash does not match hashed_result

  • This 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 errormsg so 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 uniqid was 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

type

"cancelbet" / "cancelwin"

Indicates the reversal of a previous bet or win

uniqid

cancel_123456abcdef

Strip cancel_ and look up original uniqid to revert

Best practice: treat cancel_123456abcdef as a rollback for the transaction with uniqid = 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=cancelbet

    • Retries 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 status field in JSON

  • You must ensure that duplicate handling logic is applied via uniqid

  • In 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.