This guide shows wallet developers how to implement WalletConnect Pay to process payment requests during WalletConnect session establishment.
This flow is not currently live and will be released soon. More information will be available shortly.
Overview
WalletConnect Pay allows merchants to request payments during the session connection flow. The payment request is included in the session proposal, and wallets can process the payment and return the transaction result when approving the session.
WalletConnect Pay is chain-agnostic and supports any asset on any blockchain network that can be identified using the CAIP-19 standard. This includes EVM chains, Solana, Bitcoin, Cosmos, and any other blockchain ecosystem.
Integration Flow
- Merchant calls
provider.connect({ walletPay, ... })
with payment details
- Wallet receives session proposal containing payment request
- Wallet shows payment details to user
- User approves session (optionally with payment)
- Wallet processes payment and returns result in session approval
Payment Request Schema
The walletPay
object is located at proposal.params.requests.walletPay
:
{
version: "1.0.0",
orderId?: string,
acceptedPayments: [{
asset: string, // CAIP-19 format: "eip155:1/erc20:0x..."
amount: string, // Hex-encoded: "0x186a0"
recipient: string // CAIP-10 format: "eip155:1:0x..."
}],
expiry?: number // UNIX timestamp
}
Examples
EVM (Base network, USDC token):
{
"version": "1.0.0",
"acceptedPayments": [{
"asset": "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "0x186a0",
"recipient": "eip155:8453:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}],
"expiry": 1735689600
}
Solana (USDC SPL token):
{
"version": "1.0.0",
"acceptedPayments": [{
"asset": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "0xf4240",
"recipient": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv"
}]
}
Implementation
1. Detect Payment Requests
Listen for session proposals and check for payment requests:
import { SignClientTypes } from '@walletconnect/types'
walletkit.on('session_proposal', async (proposal) => {
const walletPay = proposal?.params?.requests?.walletPay
if (walletPay) {
// Show payment approval UI
await handlePaymentProposal(proposal, walletPay)
} else {
// Regular session approval
await handleSessionProposal(proposal)
}
})
Wallets must integrate WalletConnect Wallet SDK to be compatible with WalletConnect and WalletConnect Pay. If your wallet has not yet integrated the WalletConnect Wallet SDK, please refer to the WalletConnect Wallet SDK documentation for instructions on how to integrate it.
2. Display Payment Options to the User
Parse the acceptedPayments
array and match available options against the user’s token balances. Display payment details for tokens the user can fulfill:
- Token symbol and network (parsed from CAIP-19 asset identifier)
- Amount (converted from hex to human-readable format with correct decimals)
- Recipient address
- Estimated network fees
If multiple payment options are available, prioritize by user’s balance and preferences. Allow users to switch between options or approve the session without processing payment.
3. Process Payment & Approve Session
import { EngineTypes } from '@walletconnect/types'
import { buildApprovedNamespaces } from '@walletconnect/utils'
async function approveWithPayment(proposal, walletPay, shouldProcess) {
const namespaces = buildApprovedNamespaces({
proposal: proposal.params,
supportedNamespaces: YOUR_SUPPORTED_NAMESPACES
})
const responses = []
// Process payment if user approved
if (walletPay && shouldProcess) {
const result = await executePayment(walletPay)
responses.push(result)
}
// Approve session with payment result
await walletkit.approveSession({
id: proposal.id,
namespaces,
proposalRequestsResponses: responses
})
}
4. Execute Payment
Implement payment execution based on your wallet’s architecture. The basic flow:
async function executePayment(walletPay: EngineTypes.WalletPayParams) {
const payment = walletPay.acceptedPayments[0]
// Parse payment details
const [chainId, assetType, assetAddress] = parseAsset(payment.asset)
const recipientAddress = payment.recipient.split(':')[2]
// Execute transfer (implementation depends on your wallet)
const txHash = await transferToken(
assetAddress,
recipientAddress,
payment.amount,
chainId
)
// Return result
return {
version: walletPay.version,
orderId: walletPay.orderId,
txid: txHash,
recipient: payment.recipient,
asset: payment.asset,
amount: payment.amount
}
}
Payment Result Schema
Return this structure in proposalRequestsResponses
:
{
version: string, // Echo from request
orderId?: string, // Echo from request
txid: string, // Transaction hash
recipient: string, // CAIP-10 recipient
asset: string, // CAIP-19 asset
amount: string // Hex-encoded amount
}
The merchant receives this in session.walletPayResult[0]
.
WalletConnect Pay uses CAIP standards to ensure chain-agnostic compatibility across all blockchain networks.
All assets use CAIP-19 identifiers:
{chainNamespace}:{chainId}/{assetNamespace}:{assetReference}
Examples across different chains:
Chain | Example Asset |
---|
Ethereum (USDC) | eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
Base (USDC) | eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
Optimism (USDC) | eip155:10/erc20:0x7F5c764cBc14f9669B88837ca1490cCa17c31607 |
Polygon (USDC) | eip155:137/erc20:0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 |
Arbitrum (USDC) | eip155:42161/erc20:0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8 |
Solana (USDC) | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
WalletConnect Pay supports any asset on chains with CAIP-19 specifications, including all EVM chains and Solana.
All recipients use CAIP-10 account identifiers:
{chainNamespace}:{chainId}:{address}
Examples:
- Ethereum:
eip155:1:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
- Base:
eip155:8453:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
- Solana:
solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv
Amount Encoding
Amounts are hex-encoded in the asset’s smallest unit (varies by chain):
// EVM tokens (e.g., 10 USDC with 6 decimals)
"0x" + (10 * 10**6).toString(16) // "0x989680"
// Solana tokens (e.g., 1 USDC with 6 decimals)
"0x" + (1 * 10**6).toString(16) // "0xf4240"
Error Handling
Handle common scenarios:
- Expired requests: Check
walletPay.expiry
against current timestamp
- Insufficient balance: Validate before attempting transfer
- User rejection: Allow session approval without payment
- Transaction failures: Catch errors and optionally reject session
Testing
Test with the reference implementation:
git clone https://github.com/reown-com/web-examples.git
cd web-examples
git checkout chore/wallet-pay-dapp
cd advanced/dapps/walletconnect-pay-dapp
npm install && npm run dev
Additional Resources