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
- Fund your company’s pool wallet on the TapRails dashboard
- When a customer pays, the SDK calls the backend with
customerId
- TapRails debits the pool and sends USDC to the merchant in a single transaction
- 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
| State | What happens |
|---|
| No key | TapRailsThemeProvider detects missing key and shows the setup UI automatically |
| Valid key | All payments use the stored key — no user interaction required |
| Expired key | With autoRenew: true, setup UI shows again before the next payment |
| Revoked | Call 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
| POOL | SESSION_KEY |
|---|
| Custody model | Custodial | Non-custodial |
| Wallet required | No | Yes |
| User setup flow | None | One-time approval signature |
| Per-payment UX | Instant | Instant (after setup) |
| Max exposure | Pool balance | Per-key daily limit |
| Best for | Fintechs, expense tools | Wallets, 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.