Skip to main content
The TapRails SDK supports two distinct payment execution models. The right choice depends on your product’s custody model.

POOL Mode (Custodial)

In POOL mode, payments are funded from a pre-loaded wallet managed by your company on the TapRails platform. The user doesn’t need a wallet, and no transaction signing is required at payment time.
Customer taps → SDK reads invoice → SDK calls /pay-from-pool → TapRails backend

                                                         Debit from company pool wallet

                                                         Transfer USDC to merchant wallet

When to use POOL mode

  • Your app is a closed-loop fintech (e.g., corporate expense cards, prepaid wallets)
  • You want the simplest possible integration — no wallet infrastructure required
  • You manage user balances on your backend and top up the pool wallet separately

Configuration

ContactlessCryptoSDK.initialize({
  mode: PaymentMode.POOL,
  pool: {
    customerId: 'customer_456',  // Your internal customer identifier
  },
  // ...
});

How the pool works

  1. Fund your company’s pool wallet on the TapRails dashboard
  2. When a customer pays, the SDK calls the backend with customerId
  3. TapRails debits the pool and sends USDC to the merchant in a single transaction
  4. You reconcile balances via the TapRails dashboard or webhooks
The pool wallet address and private key are managed entirely by TapRails. No key management is required on the SDK side.

SESSION_KEY Mode (Non-Custodial)

In SESSION_KEY mode, payments are funded directly from the user’s own wallet using a delegated session key. The user signs a one-time approval transaction that authorizes TapRails to spend up to a daily limit on their behalf — without requiring them to sign every individual payment.
First use:
User approves daily limit → SDK generates session keypair → Registers with backend

                                                     Session key stored in Keychain

At payment time:
Customer taps → SDK reads invoice → SDK signs payload with session key → Backend executes

                                                                  Spend from user's wallet

When to use SESSION_KEY mode

  • Your app is a non-custodial wallet or DeFi product
  • Users control their own funds on-chain
  • You want gasless, instant payments without prompting the user to sign each time
  • You use wallet infrastructure like WalletConnect, Privy, Magic, or your own MPC solution

Configuration

ContactlessCryptoSDK.initialize({
  mode: PaymentMode.SESSION_KEY,
  sessionKey: {
    walletAddress: '0x1234...abcd',  // User's wallet
    defaultDailyLimit: '100.00',     // Max USDC per day
    autoRenew: true,                 // Re-setup when key expires
    onSignTransaction: async (tx) => {
      // Your wallet integration:
      return await walletProvider.signTransaction(tx);
    },
    onSetupComplete: () => console.log('Session key ready'),
    onSetupCancel: () => console.log('User cancelled setup'),
  },
});

Session key lifecycle

StateWhat happens
No keyTapRailsThemeProvider detects missing key and shows the setup UI automatically
Valid keyAll payments use the stored key — no user interaction required
Expired keyWith autoRenew: true, setup UI shows again before the next payment
RevokedCall revokeCurrentSessionKey() to clear from Keychain and backend

Security properties

  • Session keys are ECDSA keypairs generated on-device and stored in the device Keychain
  • The private key never leaves the device
  • The daily limit caps maximum exposure if a key is compromised
  • Keys can be revoked instantly from the SDK or the TapRails dashboard

Comparison

POOLSESSION_KEY
Custody modelCustodialNon-custodial
Wallet requiredNoYes
User setup flowNoneOne-time approval signature
Per-payment UXInstantInstant (after setup)
Max exposurePool balancePer-key daily limit
Best forFintechs, expense toolsWallets, DeFi apps

Switching Modes

You can only initialize the SDK in one mode per app session. To switch modes, call ContactlessCryptoSDK.initialize() again with the new configuration (e.g., after a user logs in with a wallet). This resets the API client.