Skip to content

Withdrawals

Requesting a withdrawal deducts the funds from the specific wallet's realBalance immediately and holds them while the request awaits back-office review.

Requesting a withdrawal

javascript
const result = await sdk.wallet.requestWithdrawal({
  walletId: 'wallet_usd',       // required; which wallet to debit
  amount: 100.00,               // required; > 0, must not exceed realBalance
  currency: 'USD',              // required; MUST match the wallet's currency
  method: 'BANK_TRANSFER',     // 'BANK_TRANSFER' | 'CRYPTO' | 'CARD'
  idempotencyKey: 'wd-abc-1'    // recommended; guards against double-submit
});

console.log(`Withdrawal requested. Transaction ID: ${result.transactionId}`);
// result.status is 'PENDING'

WithdrawalPayload

FieldTypeRequiredNotes
walletIdstringyesMust be ACTIVE
amountnumberyes> 0, finite; at most the wallet's current realBalance
currencystringyesMust equal the wallet's currency (WALLET_CURRENCY_MISMATCH otherwise)
method'BANK_TRANSFER' | 'CRYPTO' | 'CARD'yesPayout channel; the union is platform-fixed in 1.0.x (see below)
payoutAccountIdstringnoPre-registered payout account to pay into; the user confirms or overrides it. Omitted → the account on file for that channel is used.
idempotencyKeystringrecommendedSame key + same payload = same transaction; same key + different payload = WALLET_DUPLICATE_REQUEST

Withdrawal state machine

StatusEntry triggerAllowed transitionsSide effects
PENDINGrequestWithdrawal succeedsCOMPLETED (back-office approves) · → REJECTED (back-office declines)Funds deducted from realBalance immediately (held)
COMPLETEDBack-office approvalterminalHeld funds paid out to the user's payout channel
REJECTEDBack-office rejectionterminalHeld funds returned to realBalance; full audit trail preserved

Rules

text
GIVEN a wallet with realBalance >= amount
WHEN requestWithdrawal is called with a matching currency and ACTIVE status
THEN realBalance drops by amount IMMEDIATELY (funds held), the ledger records
     a PENDING DEBIT entry, and the platform notifies the back office.

GIVEN two withdrawal requests submitted for the same wallet
WHEN the combined amount would exceed the wallet's realBalance
THEN the second request rejects with WALLET_INSUFFICIENT_FUNDS
     and is recorded in the ledger as REJECTED (audit trail).

GIVEN a withdrawal request in PENDING status
WHEN the back office APPROVES it
THEN the ledger entry flips to COMPLETED (held funds are paid out), and a
     PaymentEvent with type WITHDRAWAL and status COMPLETED fires.

GIVEN a withdrawal request in PENDING status
WHEN the back office REJECTS it
THEN the held amount is refunded to the wallet's realBalance, the ledger
     entry is updated to REJECTED (not deleted; full audit trail), and a
     PaymentEvent with type WITHDRAWAL and status REJECTED fires.
  1. Insufficient funds: amount > realBalance rejects with WALLET_INSUFFICIENT_FUNDS; the rejected attempt is still recorded in the ledger with a REJECTED status (full audit trail).
  2. Bonus funds are strictly separated; bonusBalance can never be withdrawn.
  3. Immediate deduction: the available balance drops when the request is created, preventing double-withdrawal while the back office reviews.
  4. Wallet status: withdrawals (and deposits) are rejected for FROZEN/CLOSED wallets (see Wallet Overview).
  5. Self-exclusion: withdrawals REMAIN available during an active self-exclusion; player funds are never trapped (see the RG enforcement contract).
  6. Concurrency-safe: the funds check and deduction are one atomic operation; parallel requests can never overdraw a wallet.

Payout destination, limits, and fees

Destination: withdrawals pay into pre-registered payout accounts referenced by payoutAccountId (the user confirms or overrides the default account for the chosen channel). Payout-account management itself (registering, verifying, and deleting bank cards / crypto addresses) is outside SDK 1.0.x scope; operators expose it via their own backoffice; getTransactions shows which account a completed payout went to. In sandbox, the destination is mocked and does not require a pre-registered account.

Limits: each payout channel has operator-configurable minAmount/maxAmount for withdrawals (enforced with the same WALLET_AMOUNT_OUT_OF_RANGE error as deposits).

Fees (1.0.x rule): withdrawal processing fees are charged off-ledger by the payout provider where applicable; the wallet's ledger records the full requested amount only, and the SDK surfaces no fee fields. If fee visibility becomes a requirement, it will be a documented spec change (breaking for the ledger's audit trail, so it will not change silently).

Payout catalog: the withdrawal method union (BANK_TRANSFER | CRYPTO | CARD) is platform-fixed in 1.0.x; not operator-configurable. Operators configure the accounts and limits behind each channel, not the set of channels.

Payout account errors: if payoutAccountId is omitted and no account is on file for the chosen channel, the request rejects with WALLET_PAYOUT_ACCOUNT_REQUIRED; the player must register an account first. If the ID is unknown, belongs to another player, or belongs to a different channel than method, the request rejects with WALLET_PAYOUT_ACCOUNT_INVALID.

Learning the outcome

Withdrawal outcomes arrive through the same channel as deposit events; subscribe with onPaymentUpdate and watch for type: 'WITHDRAWAL'.