Skip to content

Wallet & payments

The wallet is the heart of the product. It tracks balances, takes deposits in crypto and fiat, and processes withdrawals. The wallet modal is available from anywhere on the site, so a player never has to leave what they are doing to top up.

How balances work

Internally, everything is denominated in USD. Crypto and fiat amounts are converted to USD for debits and credits, and converted back to a player's chosen currency for display using live exchange rates. This keeps the betting and bonus math in one unit no matter what someone deposited.

Each account actually has two balances:

  • a real balance, the player's own money, and
  • a bonus balance, which is subject to wagering requirements.

The two are kept apart on purpose. An active bonus with unmet wagering can block real-money outflows: cashier withdrawals and player-to-player tips. Identity verification (KYC) for withdrawals blocks only when an admin has required it for that player — it is not the default. Tips always require approved KYC, independent of that admin withdrawal toggle, so P2P transfers cannot leave an unverified account. The wallet always reports a canWithdrawReal flag (false when either withdraw gate blocks), plus kycApproved, optional withdrawalBlockCode (KYC_REQUIRED | ACTIVE_BONUS), and withdrawalBlockReason alongside the numbers. The withdraw UI honors canWithdrawReal; the tip UI requires kycApproved && canWithdrawReal so a locked wagering balance or missing KYC cannot leave through a side channel. The withdraw UI shows a KYC gate instead of the payment form when an admin has required verification and it is incomplete.

Crypto deposits

For crypto, a player generates a static deposit address per currency through CryptoCloud. They can hold several addresses, and the wallet lists each one with a QR code so it is easy to send from a phone.

When funds arrive, CryptoCloud calls back to the API. The webhook is verified with a signed token before anything is credited. On a valid deposit the platform records the blockchain deposit, credits the unified USD balance, fires the deposit bonus trigger, re-evaluates the player's segments, and sends a deposit notification.

Fiat deposits

Fiat supports manual P2P bank transfer and an embedded Mercado Pago Payment Brick (configured in the admin Payments hub). The wallet loads cashier methods and deposit presets from the API — methods, limits, and sort order are configured there. Up to eight preset amount buttons can appear per currency; the default preset is auto-filled when the player selects a currency.

After entering an amount, a Mercado Pago player immediately sees two direct actions: Pay with Mercado Pago, backed by a wallet-only Checkout preference whose universal link may open the installed app, and Pay with another bank, backed by a standard Checkout Pro preference that exposes the bank-transfer and card methods enabled for the merchant account. Both preferences carry the same trusted external order reference and settle through the same reconciliation path. Because Mercado Pago does not guarantee a custom native app URI for web merchants, the universal Checkout URL is the supported deeplink; the embedded card Payment Brick remains a fallback if hosted preference creation is unavailable. Payment details always remain inside Mercado Pago.

The P2P service stores encrypted multi-account credentials, authenticates preference creation and every status lookup with the Mercado Pago access token, verifies the provider amount, currency, collector, environment, and external reference, then uses a transactional outbox to notify the casino API. Return URLs only resume the player experience and never authorize credit. Adaptive polling (10–30 seconds) is the settlement source of truth; casino credits and chargeback reversals are idempotent ledger operations.

Mercado Pago production checklist

  1. Run all P2P migrations before enabling the cashier method.
  2. Configure P2P_INTERNAL_API_SECRET, P2P_CREDENTIAL_ENCRYPTION_KEY, P2P_PUBLIC_URL, both P2P_CASINO_WEBHOOK_* values, and the matching casino-side P2P_WEBHOOK_SECRET.
  3. Add and validate at least one Mercado Pago account in the P2P admin. The public key and access token must belong to the same test or production environment.
  4. Configure P2P_CASINO_RETURN_URL as the public HTTPS player-site origin. Mercado Pago rejects localhost and non-HTTPS production return URLs.
  5. Confirm the P2P reconcile job is running (p2p-reconcile-payments, every 10 seconds) and /api/health reports ok on the P2P host.
  6. Confirm the production account exposes the intended standard Checkout Pro methods through /v1/payment_methods, then enable the inactive mercadopago:mercadopago:in ARS cashier row only after the wallet link, other-bank link, and card fallback complete end to end in staging.
  7. Give accounts the same priority to share traffic; use higher priority numbers as failover tiers.

For encryption-key rotation, set the new P2P_CREDENTIAL_ENCRYPTION_KEY and temporarily put older keys in P2P_CREDENTIAL_ENCRYPTION_KEY_PREVIOUS. Re-save account credentials under the new key before removing the previous key.

Withdrawals

A withdrawal is a request, not an instant transfer. The player picks a currency and amount and supplies a destination address; the balance is deducted immediately and the request enters a processing state for an operator to review. The player gets a notification, and they can follow the request — including a back-and-forth message thread with the back office — from its detail page.

Withdrawals only go through when the player can actually withdraw real funds (no blocking bonus / required KYC), the USD balance covers the amount, and a wallet for that currency exists. The operator side of this flow is documented under Withdrawals.

Tips

Tips move real USD balance from one player to another instantly. They always require approved KYC (resolveTipEligibility) — even when withdrawals are still open because an admin has not required verification — and they share the active-bonus lock with withdrawals. While either gate blocks, tips are rejected with the tip KYC / bonus block reason. The ledger transfer (transferRealBalance) re-checks tip eligibility under lock so a tip cannot race past a newly activated bonus or a KYC status change.

A note for local development

Because CryptoCloud depends on webhooks reaching a public HTTPS endpoint, crypto deposit flows generally need a tunnel or a staging environment. Fiat Mercado Pago deposits settle via authenticated polling on the P2P service and do not require a Mercado Pago webhook URL. The wallet UI, balances, and history all work locally regardless.