WalletConnect Pay Integration Guide for Kotlin/Android
This guide enables Android wallet developers to integrate WalletConnect Pay into applications that already have WalletKit configured.By following this guide, your wallet will be able to process crypto payment links, allowing users to pay merchants directly from your app.Before You Begin
Study First, Then Implement
This document is a reference guide, not boilerplate code to copy-paste. Before implementing:- Study your existing codebase - Understand how URI handling, signing, and navigation work in your app
- Follow established patterns - Match your app’s architecture, naming conventions, and code style
- Adapt, don’t copy - The code examples show what to do, not necessarily how your specific app should do it
Prerequisites
- WalletKit SDK integrated and initialized (
com.reown:walletkit) - Ethereum signing capability (EIP-712 typed data, personal_sign)
- Kotlin Coroutines for async operations
- Understanding of your app’s navigation and state management
Dependencies
Architecture Overview
How WalletConnect Pay Works
WalletConnect Pay enables crypto payments through payment links. The flow works as follows:WalletKit Integration
WalletKit automatically initializes WalletConnectPay duringWalletKit.initialize(). The Pay functionality is exposed through the WalletKit.Pay object:
Step 1: Payment Link Detection
Using the Official Detection Function
WalletKit providesisPaymentLink() to identify payment URIs. Always use this function rather than custom URL parsing to ensure compatibility as the protocol evolves.
Add Detection to All Entry Points
Payment link detection must be added wherever your app processes URIs:- QR Code Scanner
- Text Input / Paste
- Deep Link Handler
Important: The isPaymentLink() check must precede any generic HTTPS handlers to prevent payment links from accidentally opening in a browser.
Step 2: Implement the Payment Flow
Data Models
WalletKit exposes payment models underWallet.Model:
Payment Flow Implementation
2.1 Get Payment Options
2.2 Handle Data Collection via WebView (if required)
Some payments require user information (KYC/AML compliance). Data collection requirements are specified per payment option viacollectData. Show all options first, then handle data collection after the user selects an option:
collectData?.url, display the URL in a WebView before proceeding with signing. The hosted form handles rendering, validation, and Terms & Conditions acceptance. The WebView communicates completion via JavaScript bridge messages (IC_COMPLETE / IC_ERROR).
Important: When using the WebView approach, do not passcollectedDatatoconfirmPayment(). The WebView submits data directly to the backend.
WebView Implementation
2.3 Get Required Payment Actions
After user selects a payment option, get the signing actions:2.4 Sign the Actions
Sign eachWalletRpcAction with the wallet’s private key:
Critical: Pass raw JSON strings directly to signing APIs. Do not parse and reconstruct the JSON data, as this can cause transformation issues leading to signature verification failures.
2.5 Confirm Payment
Submit signatures and collected data to confirm the payment:Step 3: State Management
Recommended State Machine
Implement a state machine to manage the payment flow:ViewModel Implementation
Step 4: UI Components
Required Screens
- Loading Screen - Show while fetching payment options
- Options Screen - List of payment options (tokens/chains). Show an “Info required” badge on options that have
collectData != null - Data Collection Screen - WebView for KYC/compliance data (shown after selecting an option that requires IC)
- Processing Screen - Show while signing and confirming
- Success Screen - Payment completed successfully
- Error Screen - Handle failures gracefully
Jetpack Compose Example
Utility Functions
Format Payment Amount
Format Expiry Time
Validate Date Input
Error Handling
Common Errors
WalletKit exposes typed errors for payment operations:Error Handling Strategy
Troubleshooting
Payment Options Empty
Symptom:getPaymentOptions returns an empty options list.
Causes:
- Wallet address not supported by merchant
- Chain not supported for this payment
- Payment link already used or expired
- Verify CAIP-10 account format:
eip155:{chainId}:{address} - Include all chains your wallet supports
- Check if payment link is still valid
Signature Verification Failed
Symptom:confirmPayment fails with signature verification error.
Causes:
- Incorrect EIP-712 signing implementation
- JSON transformation altering the typed data
- Wrong address used for signing
- Use
StructuredDataEncoderfor EIP-712 hashing - Pass raw JSON strings to signing without parsing/reconstruction
- Verify the signing address matches the requested address in params
Wrong Chain
Symptom: Transaction fails or signing produces unexpected results. Causes:- Not using the chainId from
WalletRpcAction - Signing with wrong network context
- Always use
action.chainIdto determine which network to sign for - Ensure your wallet’s signing context matches the action’s chain
Payment Status Polling
ForPROCESSING status, implement polling:
Complete Flow Example
Reference Implementation
For a complete working example, see the sample wallet implementation:sample/wallet/src/main/kotlin/com/reown/sample/wallet/ui/routes/dialog_routes/payment/PaymentViewModel.ktsample/wallet/src/main/kotlin/com/reown/sample/wallet/ui/routes/dialog_routes/payment/PaymentRoute.kt