debit — Withdrawal
Deducts an amount from the player's balance when the player bets or takes a seat. The platform does not retry debits. If the outcome is uncertain, it treats the debit as a failure and immediately sends a rollback.
POST {wallet_base_url}/debitWhen It Is Called
reason | When | round_id | Games |
|---|---|---|---|
bet | Bet | rnd_… | Baccarat, Blackjack, Speed Hold'em |
ante | Ante | rnd_… | Speed Hold'em |
double | Double down | rnd_… | Blackjack |
split | Split | rnd_… | Blackjack |
buy_in | Taking a seat at a table (buy-in) | tss_… | Buy-in-flow games (Texas Hold'em, Pot-Limit Omaha, Live Hold'em, Matgo, Go-Stop, Seotda, Tong-its, Red Dog) |
top_up | Adding chips while seated | tss_… | Buy-in-flow games |
- In bet-flow games, a single round may receive multiple debits. Debits in the same round use the same
round_id. - Buy-in-flow games do not debit per hand. Debits arrive only when taking a seat or adding chips.
- New
reasonvalues may be added. If you receive an unknown value, do not reject it; process it as a regular withdrawal.
Request
Headers are the same as the common headers.
| Field | Type | Required | Description |
|---|---|---|---|
tx_id | string | ● | Platform transaction ID (tx_ + 32 hex digits). Idempotency key |
external_id | string | ● | Operator-side player ID |
player_id | string | ● | Platform player ID (pl_…), for reference |
currency | string | ● | Currency code |
amount | integer | ● | Amount to deduct, integer in the minor unit, 1 or more |
reason | string | ● | A value from the table above |
game_code | string | ● | Game code |
table_id | string | ● | Table ID (tbl_…) |
round_id | string | ● | Round ID (rnd_…) or table session ID (tss_…) |
operator_session_id | string | null | ● | The value sent at game launch. null if none was sent |
created_at | string | ● | Time the platform created the transaction (UTC, milliseconds) |
{
"amount": 5000,
"created_at": "2026-10-19T02:10:00.123Z",
"currency": "PHP",
"external_id": "u-102938",
"game_code": "live_baccarat",
"operator_session_id": "s-88af21",
"player_id": "pl_0199e8b4f2a37c1d8e5b6a4f3c2d1e0b",
"reason": "bet",
"round_id": "rnd_0199f2a0b1c27d3e8f4a5b6c7d8e9f01",
"table_id": "tbl_0199a1b2c3d47e5f8a9b0c1d2e3f4a5b",
"tx_id": "tx_0199f2a1c3d47e8b9a6f1e2d3c4b5a69"
}{
"amount": 100000,
"created_at": "2026-10-19T02:12:41.507Z",
"currency": "PHP",
"external_id": "u-102938",
"game_code": "holdem_nlh",
"operator_session_id": "s-88af21",
"player_id": "pl_0199e8b4f2a37c1d8e5b6a4f3c2d1e0b",
"reason": "buy_in",
"round_id": "tss_0199f29e7c6b4a5d8e3f2a1b0c9d8e7f",
"table_id": "tbl_0199a1b5d0e47f2a9b8c7d6e5f4a3b2c",
"tx_id": "tx_5a3c9e1f0b7d4e2a8c6f1b3d5e7a9c0e"
}The actual body is single-line JSON with no whitespace. The examples above are split across lines for readability.
Response
| Field | Type | Required | Description |
|---|---|---|---|
status | string | ● | Result code |
balance | integer | ● when OK | Balance after the deduction |
operator_tx_id | string | Operator-side transaction ID |
{ "status": "OK", "balance": 1245000, "operator_tx_id": "w-99812" }{ "status": "INSUFFICIENT_FUNDS", "balance": 3000 }{ "status": "PLAYER_BLOCKED" }{ "status": "TX_ALREADY_ROLLED_BACK" }{ "status": "UNKNOWN_ERROR" }Platform Behavior by status
| status | When the operator uses it | Platform handling |
|---|---|---|
OK | When the amount was deducted (for a repeated request with the same tx_id, the original result) | Bet or seat confirmed; the response balance is shown on screen |
INSUFFICIENT_FUNDS | When the balance is less than amount | Definitive rejection. The player is told the balance is insufficient |
LIMIT_EXCEEDED | When the operator's responsible gambling limit (bet limit, loss limit, etc.) is exceeded | Definitive rejection. The player is told a limit was exceeded |
PLAYER_BLOCKED | When the player is blocked or self-excluded | Definitive rejection |
PLAYER_NOT_FOUND | When the player does not exist | Definitive rejection |
CURRENCY_MISMATCH | When the request currency differs from the player's currency | Definitive rejection |
TX_ALREADY_ROLLED_BACK | When a rollback for this tx_id was received first | Definitive rejection |
INVALID_REQUEST | Missing fields or malformed values, or the same tx_id with different contents | Definitive rejection |
INVALID_SIGNATURE | Signature verification failed | Definitive rejection |
UNKNOWN_ERROR | An error where it is uncertain whether the deduction happened | Treated as failure + immediate rollback (timeout) |
(3-second timeout, non-HTTP-200, connection failure, invalid JSON, empty status) | — | Treated as failure + immediate rollback (timeout) |
- On a definitive rejection, the platform does not send a rollback. Use a rejection status only when you are certain the balance was not touched.
- Status values not in the table above are treated as definitive rejections. If it is uncertain whether the debit was processed, always respond with
UNKNOWN_ERRORor HTTP 5xx. - A rejected bet or seat is shown as an error on the player's screen. Insufficient funds and limit exceeded are shown with that exact reason; other reasons may, depending on the game, be grouped under a wallet error (
WALLET_UNAVAILABLE). - You may include or omit
balancein a rejection response. The platform does not use the balance from rejection responses.
Processing Order
This is the recommended order. Perform the balance deduction and the transaction record within a single DB transaction.
- Verify the signature → on failure,
INVALID_SIGNATURE - Validate fields (
tx_idandexternal_idpresent,amountis an integer of 1 or more) → on failure,INVALID_REQUEST - If a record for the same
tx_idexists → return the stored response as is (both successes and rejections) - Lock the player row → if missing,
PLAYER_NOT_FOUND - If this
tx_idis in the rollback markers (a record that the rollback arrived first) →TX_ALREADY_ROLLED_BACK - Check the currency →
CURRENCY_MISMATCH - Blocked or self-excluded →
PLAYER_BLOCKED; responsible gambling limit →LIMIT_EXCEEDED - Check the balance →
INSUFFICIENT_FUNDS - Deduct and return
OK+ the post-deductionbalance+operator_tx_id
Record rejection results by tx_id as well, and return the same rejection if the same tx_id arrives again.
Notes
Respond within 3 seconds
If the platform does not receive a debit response within 3 seconds, it rejects the bet or seat and immediately sends a rollback for the same amount (reason: "timeout", ref_tx_id = this debit). If the debit was eventually processed on the operator side, it must be reversed by that rollback; if the debit is still being processed, it may overlap with the rollback. Process both requests inside a per-player lock, and perform the rollback marker check (step 5) after acquiring the lock. For details on each case, see rollback.
The same debit is not sent twice, but be prepared anyway
The platform never resends a debit once sent. Even so, proxies or load balancers in front of the operator sometimes resend requests, so be sure to implement the idempotent handling in step 3.
Leaving right after sitting down
In buy-in-flow games, if the player leaves the seat before the debit result arrives, the platform returns the successful buy-in amount as a separate credit (reason: "cash_out", a different tx_id). This is not a cancellation (rollback) of the debit, so simply apply it as is.