GA calls your wallet: the actions
GA sends POST to https://<your-host>/v2/wallet/<action>. Ten actions exist. Five are mandatory.
| Action | Mandatory | What GA asks |
|---|---|---|
get_balance | yes | ”How much can this player play with?” |
debit | yes | ”Take the stake for this bet.” |
credit | yes | ”Pay this win.” |
rollback | yes | ”Undo this earlier operation.” |
reconcile | yes | ”Did this operation go through?” |
authenticate | no | ”This player is opening a game. Who are they and what’s their balance?” |
debit_credit | no | ”Take the stake and pay the win in one step.” |
close_round | no | ”This round is over. Here are the totals.” |
settle_grant | no (mandatory if you issue free rounds) | “This free-round package is finished. Here is the total win.” |
notify | no | ”Something non-monetary happened.” |
For an optional action you don’t support, return the error envelope with ERROR_CODE_UNSUPPORTED_ACTION on HTTP 200 or 404. GA reads the envelope and stops calling that action. A bare 404 without the envelope is “no answer”, and GA retries it.
The examples below show the envelope reduced to the fields that matter. ts, operator_id, correlation, and the headers are as in chapter 2. All values are illustrative.
get_balance
Return the playable balance in the requested currency. Change nothing.
{
"request_id": "req-0101",
"action": "get_balance",
"payload": {
"meta": {
"request_id": "req-0101",
"op_id": "op-bal-1001",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0"
},
"currency": "EUR"
}
}
{
"status": "ok",
"data": {
"balance": {
"currency": "EUR",
"amount": 15000,
"exponent": 2
},
"bonus_balance": {
"currency": "EUR",
"amount": 500,
"exponent": 2
}
}
}
Refuse only for: player not found, currency mismatch, invalid request.
authenticate (optional)
When: the player opens a game. GA sends the launch_token you passed at launch. Return who the player is, the currency, and the balance. Keep the token valid: it comes back in every wallet call of the session.
{
"request_id": "req-0102",
"action": "authenticate",
"payload": {
"meta": {
"request_id": "req-0102",
"op_id": "op-auth-1002",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0",
"launch_token": "lt-abcdef123456"
}
}
}
{
"status": "ok",
"data": {
"player_ref": "player-10428",
"currency": "EUR",
"balance": {
"currency": "EUR",
"amount": 15000,
"exponent": 2
},
"bonus_balance": {
"currency": "EUR",
"amount": 500,
"exponent": 2
},
"attributes": {
"country": "DE",
"nickname": "lucky_ann"
}
}
}
Refuse for: unknown or expired token (SESSION_EXPIRED), blocked player (PLAYER_BLOCKED), player not found.
debit
Do: take the stake. Return your transaction id, the balance after, the amount debited.
Refuse when:
amountis zero or negative:INVALID_REQUEST.- the balance can’t cover it:
INSUFFICIENT_FUNDS. Final: GA doesn’t resend that bet. - the session or token is expired or missing on a call that names a session:
SESSION_EXPIRED/INVALID_REQUEST. - the player is blocked or over a limit:
PLAYER_BLOCKED/LIMIT_EXCEEDED. - the round is already closed or voided:
BUSINESS_REJECTED.
Never refuse a repeated debit (Rule 1). A debit is also how a balance correction from the game provider reaches you, sometimes outside a live session. Apply it the same way.
{
"request_id": "req-0103",
"action": "debit",
"payload": {
"meta": {
"request_id": "req-0103",
"op_id": "op-bet-48912",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0",
"launch_token": "lt-abcdef123456",
"round_id": "round-82721",
"provider_ref": "spin-99182"
},
"money": {
"currency": "EUR",
"amount": 100,
"exponent": 2
}
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982103",
"balance_after": {
"currency": "EUR",
"amount": 14900,
"exponent": 2
},
"debited": {
"currency": "EUR",
"amount": 100,
"exponent": 2
}
}
}
credit
Do: add the win. Rule 3 applies: never refuse for session, block, or limits. Return your transaction id and the balance after.
amountmay be0for a losing spin that closes the round. Answerokwith the unchanged balance.kindsays what the payout is:CREDIT_KIND_WIN,_BONUS,_JACKPOT,_PROMO,_FREE_ROUND,_TOURNAMENT,_CASHBACK,_ADJUSTMENT.components[]is an optional breakdown (KIND_BASE,KIND_JACKPOT,KIND_PROMO,KIND_BONUS,KIND_CONTRIBUTION). The parts sum tomoney.round_finish: truemeans this credit ends the round. Still accept a credit into a round you already closed.campaign_refnames the provider promo on aFREE_ROUNDcredit.
Refuse only for: player not found, currency mismatch, invalid request, idempotency conflict, unknown original, already rolled back.
{
"request_id": "req-0104",
"action": "credit",
"payload": {
"meta": {
"request_id": "req-0104",
"op_id": "op-win-48913",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0",
"launch_token": "lt-abcdef123456",
"round_id": "round-82721",
"provider_ref": "spin-99182"
},
"money": {
"currency": "EUR",
"amount": 2500,
"exponent": 2
},
"kind": "CREDIT_KIND_WIN",
"round_finish": true
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982104",
"balance_after": {
"currency": "EUR",
"amount": 17400,
"exponent": 2
}
}
}
debit_credit (optional)
Do: take the stake and pay the win in one atomic step. Check the stake against the current balance first, exactly like a debit. If it doesn’t cover debit_money, refuse the whole call with INSUFFICIENT_FUNDS and change nothing. Never apply only one half.
{
"request_id": "req-0105",
"action": "debit_credit",
"payload": {
"meta": {
"request_id": "req-0105",
"op_id": "op-step-48914",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0",
"launch_token": "lt-abcdef123456",
"round_id": "round-82721",
"provider_ref": "spin-99183"
},
"debit_money": {
"currency": "EUR",
"amount": 100,
"exponent": 2
},
"credit_money": {
"currency": "EUR",
"amount": 300,
"exponent": 2
},
"credit_kind": "CREDIT_KIND_WIN",
"round_finish": true
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982105",
"balance_after": {
"currency": "EUR",
"amount": 17600,
"exponent": 2
},
"debited": {
"currency": "EUR",
"amount": 100,
"exponent": 2
}
}
}
rollback
Do: undo the operation named by original_op_id. Rule 4 applies when you don’t know it. Return your transaction id, the balance after, and original_found.
- Rolling back a debit is always for the full stored amount: return the stake to the player.
- Rolling back a credit takes money back.
debit_modesays what to do when the balance is too low.DEBIT_MODE_REJECTmeans refuse withINSUFFICIENT_FUNDS. GA’s own rollbacks use this mode.DEBIT_MODE_ALLOW_NEGATIVEmeans go negative.DEBIT_MODE_PARTIALmeans take what’s there, down to zero, and report the taken amount indebited.partial: truemarks a partial rollback of a credit. - A second rollback of the same original returns the first answer and moves nothing.
- If you’re still committing the original, answer an error envelope with
retryable: true. GA comes back. - If the player or currency doesn’t match the original, refuse with
INVALID_REQUESTorCURRENCY_MISMATCHand move nothing.
Never refuse a rollback for session, block, or limits. Any final refusal you do send (for example INSUFFICIENT_FUNDS under DEBIT_MODE_REJECT) stops GA’s retries at once and puts the operation into manual review on GA’s side.
{
"request_id": "req-0106",
"action": "rollback",
"payload": {
"meta": {
"request_id": "req-0106",
"op_id": "op-rb-48915",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0",
"launch_token": "lt-abcdef123456",
"round_id": "round-82721",
"provider_ref": "spin-99182"
},
"original_op_id": "op-bet-48912",
"original_kind": "ORIGINAL_KIND_DEBIT",
"money": {
"currency": "EUR",
"amount": 100,
"exponent": 2
}
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982106",
"balance_after": {
"currency": "EUR",
"amount": 17700,
"exponent": 2
},
"original_found": true
}
}
Unknown original: same shape with "original_found": false, no money moved, and the id stored as rolled back.
close_round (optional)
Do: record that the round is over. net_win, bet_total, win_total are for your reports. No money moves on this call.
{
"request_id": "req-0107",
"action": "close_round",
"payload": {
"meta": {
"request_id": "req-0107",
"op_id": "op-close-48916",
"player_ref": "player-10428",
"round_id": "round-82721"
},
"net_win": {
"currency": "EUR",
"amount": 200,
"exponent": 2
},
"bet_total": {
"currency": "EUR",
"amount": 100,
"exponent": 2
},
"win_total": {
"currency": "EUR",
"amount": 300,
"exponent": 2
}
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982107",
"balance_after": {
"currency": "EUR",
"amount": 17700,
"exponent": 2
}
}
}
reconcile
When: GA got no clear answer to an operation and asks what happened. Do: look up original_op_id and report. Change nothing and remember nothing. This is a read. Never return UNKNOWN_ORIGINAL here.
Your record of original_op_id | Return state |
|---|---|
| not there | RECONCILE_STATE_NOT_APPLIED |
| still being committed | RECONCILE_STATE_UNKNOWN |
| applied | RECONCILE_STATE_APPLIED with the original operator_tx_id and balance_after |
| rolled back, or remembered as rolled back (Rule 4) | RECONCILE_STATE_NOT_APPLIED |
{
"request_id": "req-0110",
"action": "reconcile",
"payload": {
"meta": {
"request_id": "req-0110",
"op_id": "op-rec-48918",
"player_ref": "player-10428"
},
"original_op_id": "op-bet-48912"
}
}
{
"status": "ok",
"data": {
"state": "RECONCILE_STATE_APPLIED",
"operator_tx_id": "tx-op-982103",
"balance_after": {
"currency": "EUR",
"amount": 14900,
"exponent": 2
}
}
}
settle_grant (mandatory if you issue free rounds)
When: a grant you issued with issue_grant (§4.4) is finished: exhausted, expired, or cancelled with a win. Do: credit total_win to the player, once per grant_id. The call is idempotent by op_id. GA sent no debits and no credits for the rounds, so this call is the only place the win reaches the player. total_win: 0 needs only an ok. Exception (Money Path Rules §2.10 item 7): a win of a round played before the grant ended can reach GA after the grant ended (settled via settle_grant, or cancelled or expired before payout). Such a win arrives as a separate credit with kind = CREDIT_KIND_FREE_ROUND and campaign_ref set to the grant_id, idempotent by op_id like any other credit. A new round reported on a grant that has already ended is still refused to GA and never reaches you.
Two free-round mechanisms exist and they never overlap for the same win:
| Mechanism | Who starts it | How the win reaches your wallet |
|---|---|---|
Grant you issue (issue_grant) | you | one settle_grant with total_win at the end |
| Promo free spins from the game provider | the provider or a GA campaign | an ordinary credit with CREDIT_KIND_FREE_ROUND and campaign_ref per winning spin |
Free-round wins may arrive with no session_id and no launch_token. Accept them (Rule 3).
{
"request_id": "req-0108",
"action": "settle_grant",
"payload": {
"meta": {
"request_id": "req-0108",
"op_id": "op-grant-7781",
"player_ref": "player-10428"
},
"grant_id": "grant-7781",
"total_win": {
"currency": "EUR",
"amount": 1250,
"exponent": 2
},
"rounds_played": 20
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "tx-op-982108",
"balance_after": {
"currency": "EUR",
"amount": 18950,
"exponent": 2
}
}
}
notify (optional)
Do: record the event and answer ok. Nothing to move. GA sends it once and doesn’t retry.
Kinds: NOTIFY_KIND_FREE_ROUNDS_STARTED, _TOKEN_RESET, _SESSION_EXPIRED, _REALITY_CHECK, _PRIZE_AWARDED, _FREESPIN_ISSUED, _FREESPIN_FINISHED, _BONUS_BUY_FINISHED.
{
"request_id": "req-0109",
"action": "notify",
"payload": {
"meta": {
"request_id": "req-0109",
"op_id": "op-ntf-48917",
"player_ref": "player-10428",
"session_id": "0198a1cb-4f37-7ee8-8e7d-08d39925aec0"
},
"kind": "NOTIFY_KIND_SESSION_EXPIRED",
"data": {
"attributes": {
"reason": "idle_timeout"
}
}
}
}
{
"status": "ok",
"data": {
"operator_tx_id": "ntf-op-1"
}
}
Reference
- POST
/v2/wallet/get_balance— Get player balance: parameters, errors, code samples, try it - POST
/v2/wallet/authenticate— Authenticate player session: parameters, errors, code samples, try it - POST
/v2/wallet/debit— Debit player balance (bet): parameters, errors, code samples, try it - POST
/v2/wallet/credit— Credit player balance (win/bonus): parameters, errors, code samples, try it - POST
/v2/wallet/debit_credit— Atomic debit and credit: parameters, errors, code samples, try it - POST
/v2/wallet/rollback— Rollback transaction: parameters, errors, code samples, try it - POST
/v2/wallet/close_round— Close game round: parameters, errors, code samples, try it - POST
/v2/wallet/settle_grant— Settle free-round grant: parameters, errors, code samples, try it - POST
/v2/wallet/reconcile— Reconcile uncertain transaction: parameters, errors, code samples, try it - POST
/v2/wallet/notify— Non-financial notification: parameters, errors, code samples, try it