Appearance
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
| Member | Returns | Description |
|---|---|---|
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 fn | Payment 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
| Status | Entry trigger | Allowed transitions | Effect on deposits/withdrawals |
|---|---|---|---|
ACTIVE | Wallet creation | → FROZEN (e.g., operator risk review, KYC review, suspected-fraud investigation) · → CLOSED (account closure) | Allowed |
FROZEN | Platform freeze (risk/compliance review) | → ACTIVE (review cleared) · → CLOSED | Rejected with WALLET_FROZEN |
CLOSED | Account closure | terminal | Rejected 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:
| Code | Error class | HTTP status | Trigger condition | Retryable |
|---|---|---|---|---|
WALLET_NOT_FOUND | WalletNotFoundError | 404 | walletId does not exist or belongs to another user | No |
WALLET_FROZEN | WalletFrozenError | 409 | Deposit/withdrawal on a FROZEN wallet | No (until unfrozen) |
WALLET_CLOSED | WalletClosedError | 409 | Deposit/withdrawal on a CLOSED wallet | No |
WALLET_METHOD_NOT_FOUND | PaymentMethodNotFoundError | 404 | Unknown methodId | No |
WALLET_CURRENCY_MISMATCH | CurrencyMismatchError | 400 | Payload, method, and wallet currencies disagree | No (fix input) |
WALLET_INVALID_AMOUNT | InvalidAmountError | 400 | amount <= 0 or non-finite | No (fix input) |
WALLET_AMOUNT_OUT_OF_RANGE | AmountOutOfRangeError | 400 | Amount outside the method's minAmount/maxAmount | No (fix input) |
WALLET_INSUFFICIENT_FUNDS | InsufficientFundsError | 400 | Withdrawal exceeds the wallet's realBalance (a REJECTED ledger entry is recorded) | No (after top-up) |
WALLET_PAYMENT_NOT_FOUND | PaymentIntentNotFoundError | 404 | verifyDeposit with an unknown transactionId | No |
WALLET_INVALID_OTP | InvalidOtpError | 401 | Wrong 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_REQUEST | DuplicateRequestError | 409 | Same idempotency key reused with a DIFFERENT payload | No (use a new key) |
WALLET_PAYOUT_ACCOUNT_REQUIRED | PayoutAccountRequiredError | 400 | Withdrawal without payoutAccountId and no account on file for the channel | No (register an account) |
WALLET_PAYOUT_ACCOUNT_INVALID | PayoutAccountInvalidError | 400 | Unknown, foreign, or wrong-channel payoutAccountId | No (fix input) |
Operator-configurable values
| Value | Type | Default / range | Effect |
|---|---|---|---|
| Payment method catalog | per method | operator-defined | Which methods appear in getPaymentMethods(), per region; each with its category, currency, and flags |
minAmount / maxAmount per method | number (method currency) | operator-defined | Deposit envelope enforced on initiateDeposit |
requiresOtp per method | boolean | false | When true, the method's deposit flow starts at REQUIRES_OTP instead of its category default |
Withdrawal minAmount / maxAmount per payout channel | number (wallet currency) | operator-defined | Withdrawal 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.