Skip to content

Wallet Overview & Multi-Currency

The Wallet module handles all financial data: multi-currency wallets, deposits, withdrawals, and an immutable per-wallet ledger. A single user can hold balances in multiple currencies simultaneously (e.g., a USD wallet and a EUR wallet).

All wallet methods require an authenticated session. If the access token is expired, the SDK silently refreshes and retries once; if the session is gone, you get a typed auth error; never wallet data for an anonymous caller.

Public surface

MemberReturnsDescription
getWallets()Promise<Wallet[]>The user's wallets
getPaymentMethods()Promise<PaymentMethod[]>Deposit methods available to the user
initiateDeposit(payload)Promise<PaymentIntent>Start a deposit (see Dynamic Deposits)
verifyDeposit(transactionId, code?)Promise<PaymentIntent>Finalize a redirect/OTP deposit
requestWithdrawal(payload)Promise<WithdrawalRequest>Start a withdrawal (see Withdrawals)
getTransactions(walletId, query?)Promise<Transaction[]>Ledger page (see Transaction History)
onPaymentUpdate(listener)unsubscribe fnPayment state changes (see Payment Events)

Typed structures

typescript
interface Wallet {
  id: string;          // opaque wallet identifier
  currency: string;    // e.g. 'USD', 'EUR', 'BTC'
  isDefault: boolean;  // the primary wallet shown by default
  realBalance: number;  // deposited cash; withdrawable
  bonusBalance: number;// promotional funds; NOT withdrawable
  status: 'ACTIVE' | 'FROZEN' | 'CLOSED';
}

interface PaymentMethod {
  id: string;                  // e.g. 'upi_qr', 'stripe_card'; pass to initiateDeposit
  category: PaymentMethodCategory; // closed union; see below
  name: string;                // display name, e.g. 'UPI QR'
  currency: string;            // the method's processing currency; must match the wallet's
  requiresOtp?: boolean;       // operator-configurable: gate the flow behind a one-time code
  iconUrl?: string;            // optional icon for your payment picker
  minAmount?: number;          // operator-configurable minimum deposit (method currency)
  maxAmount?: number;          // operator-configurable maximum deposit
  fields?: PaymentMethodFieldDescriptor[]; // extra form fields your UI should collect
}

type PaymentMethodCategory =
  | 'CARD'          // credit/debit card; 3D Secure redirect flow
  | 'HOSTED_PAGE'   // provider-hosted checkout page
  | 'UPI'           // UPI intent/QR
  | 'QR_CODE'       // generic QR-code payment
  | 'MOBILE_WALLET' // provider app redirect (e.g. GCash)
  | 'CRYPTO'        // on-chain transfer
  | 'BANK_TRANSFER'; // manual bank transfer

interface PaymentMethodFieldDescriptor {
  key: string;                              // field name to send back in `fields` data
  label: string;                           // display label for your form
  type: 'TEXT' | 'NUMBER' | 'SELECT';      // input kind to render
  required: boolean;                        // whether the user must fill it
  options?: string[];                       // present when type = SELECT
}

Method currency: each method processes in exactly one currency. A method can only be used with a wallet of the same currency; filter your payment picker by the selected wallet's currency, and initiateDeposit rejects mismatches with WALLET_CURRENCY_MISMATCH (the payload currency, method currency, and wallet currency must all agree).

Wallet status state machine

StatusEntry triggerAllowed transitionsEffect on deposits/withdrawals
ACTIVEWallet creationFROZEN (e.g., operator risk review, KYC review, suspected-fraud investigation) · → CLOSED (account closure)Allowed
FROZENPlatform freeze (risk/compliance review)ACTIVE (review cleared) · → CLOSEDRejected with WALLET_FROZEN
CLOSEDAccount closureterminalRejected with WALLET_CLOSED

Freezes are a risk/compliance tool. They never happen as a side effect of bonus play; bonus funds are separated at the balance level (bonusBalance), not by freezing the wallet.

Only the platform moves wallet status; the client can observe it, never set it.

text
GIVEN a wallet whose status is not ACTIVE
WHEN initiateDeposit or requestWithdrawal targets that wallet
THEN the call rejects (WALLET_FROZEN / WALLET_CLOSED) and NO ledger entry is created.

Fetching wallets

javascript
const wallets = await sdk.wallet.getWallets();

wallets.forEach(wallet => {
  console.log(`${wallet.currency}: real ${wallet.realBalance}, bonus ${wallet.bonusBalance} (${wallet.status})`);
});

Wallet ID: every action (deposit, withdraw, history) requires a walletId. Prompt the user to select a wallet when they hold more than one.

Wallet error contract

Common errors (NETWORK_ERROR, TIMEOUT, UNAUTHORIZED, FORBIDDEN, SESSION_EXPIRED) are defined in the Error Reference; wallet-specific codes are:

CodeError classHTTP statusTrigger conditionRetryable
WALLET_NOT_FOUNDWalletNotFoundError404walletId does not exist or belongs to another userNo
WALLET_FROZENWalletFrozenError409Deposit/withdrawal on a FROZEN walletNo (until unfrozen)
WALLET_CLOSEDWalletClosedError409Deposit/withdrawal on a CLOSED walletNo
WALLET_METHOD_NOT_FOUNDPaymentMethodNotFoundError404Unknown methodIdNo
WALLET_CURRENCY_MISMATCHCurrencyMismatchError400Payload, method, and wallet currencies disagreeNo (fix input)
WALLET_INVALID_AMOUNTInvalidAmountError400amount <= 0 or non-finiteNo (fix input)
WALLET_AMOUNT_OUT_OF_RANGEAmountOutOfRangeError400Amount outside the method's minAmount/maxAmountNo (fix input)
WALLET_INSUFFICIENT_FUNDSInsufficientFundsError400Withdrawal exceeds the wallet's realBalance (a REJECTED ledger entry is recorded)No (after top-up)
WALLET_PAYMENT_NOT_FOUNDPaymentIntentNotFoundError404verifyDeposit with an unknown transactionIdNo
WALLET_INVALID_OTPInvalidOtpError401Wrong one-time code on a REQUIRES_OTP deposit (intent stays REQUIRES_OTP; attempt counter runs; limit → the common TOO_MANY_ATTEMPTS error)Yes (mind the attempt limit)
WALLET_DUPLICATE_REQUESTDuplicateRequestError409Same idempotency key reused with a DIFFERENT payloadNo (use a new key)
WALLET_PAYOUT_ACCOUNT_REQUIREDPayoutAccountRequiredError400Withdrawal without payoutAccountId and no account on file for the channelNo (register an account)
WALLET_PAYOUT_ACCOUNT_INVALIDPayoutAccountInvalidError400Unknown, foreign, or wrong-channel payoutAccountIdNo (fix input)

Operator-configurable values

ValueTypeDefault / rangeEffect
Payment method catalogper methodoperator-definedWhich methods appear in getPaymentMethods(), per region; each with its category, currency, and flags
minAmount / maxAmount per methodnumber (method currency)operator-definedDeposit envelope enforced on initiateDeposit
requiresOtp per methodbooleanfalseWhen true, the method's deposit flow starts at REQUIRES_OTP instead of its category default
Withdrawal minAmount / maxAmount per payout channelnumber (wallet currency)operator-definedWithdrawal envelope enforced on requestWithdrawal (WALLET_AMOUNT_OUT_OF_RANGE)

Wallet currencies, wallet creation, and balance arithmetic are platform-fixed; not configurable. Bonus funds are always non-withdrawable; a compliance-mandated platform rule, deliberately NOT operator-configurable.