Payment Integration for Indian Apps
India's payment ecosystem is unique: UPI dominates, wallets are widespread, and card usage is growing. A complete payment solution handles all three.
UPI Integration
UPI (Unified Payments Interface) is the fastest-growing payment method in India. It's simple, instant, and ubiquitous.
Integration approaches:
- Intent-based: Launch any UPI app (Google Pay, PhonePe, WhatsApp Pay). Your app creates a payment intent; user confirms in their UPI app; result returns to your app.
upiString = "upi://pay?pa=user@upi&pn=NexaEx&am=100&tn=Order123"
Intent intent = new Intent(Intent.ACTION_VIEW)
intent.setData(Uri.parse(upiString))
startActivityForResult(intent, UPI_REQUEST_CODE)
- API-based: Use a payment gateway like Razorpay or BillDesk. They handle UPI payments and settlement.
Advantages of gateway: Easier testing, settlement to bank account, compliance handled.
Advantages of direct intent: Fastest, no gateway fees.
Wallet Integration
Google Pay and PhonePe both offer in-app wallet payment APIs. Users add cards once, then pay with one tap.
Google Pay integration: Implement in-app purchases and payments using PaymentsClient. Handles tokenization, encryption, and settlement.
NPCI guidelines: Wallets must integrate with UPI for redemption. Stored value alone (like old Paytm) isn't compliant.
Card Payments
Most payment gateways tokenize cards for compliance and convenience.
Never store raw card data. This triggers PCI-DSS compliance requirements and legal liability. Use gateway tokenization APIs:
// Razorpay tokenization
const cardData = {
number: '4111111111111111',
expiry: '12/25',
cvv: '123'
}
const token = await gateway.tokenizeCard(cardData)
// Store token, use for future payments
Security Best Practices
Data at rest: Encrypt sensitive data before storing. Use platform encryption (Android Keystore, iOS Keychain) for cryptographic keys.
Data in transit: HTTPS/TLS everywhere. Pinned certificates prevent man-in-the-middle attacks.
API keys: Never hardcode API keys. Use backend servers to exchange app authentication for temporary credentials.
Compliance: PCI-DSS, RBI guidelines, NPCI mandates. Let payment gateways handle most of this; they're specialized.
Handling Failures and Retries
Payment systems are distributed. Networks fail, timeouts occur.
// After user initiates payment:
1. Record transaction in local database (pending state)
2. User confirms payment in UPI app
3. Receive callback (success/failure)
4. Update local state
5. On app close, sync pending transactions
6. On re-open, check server for status (idempotent check)
Never re-charge a user because their payment seemed to fail. Always query server-side status first.
Settlement and Reconciliation
Payment gateways typically settle 24-48 hours after payment. Build reconciliation logic:
Daily reconciliation:
1. Fetch settled transactions from gateway API
2. Compare against your transaction log
3. Flag discrepancies (reversed, refunded, failed)
4. Update balance accordingly
Indian-Specific Patterns
Low-connectivity handling: UPI payments work offline partially (intent launches); ensure app gracefully handles network drops during payment confirmation.
Prepaid wallets: Some users prefer buying prepaid credit then spending it. Support cash-in via ATM transfers, bank deposits, or retail vouchers.
In-app cash out: Some apps (marketplaces, freelance platforms) let users withdraw earnings. Implement bank account verification, KYC checks, and daily/monthly limits.
Frequently asked questions
Should I integrate UPI directly or use a payment gateway?
Direct UPI integration is simpler and cheaper (no gateway fees), but gateways handle testing, settlement, and compliance. For new apps, gateways are recommended.
Can I store credit card data in my app?
No. Never store raw card data. This triggers PCI-DSS compliance and liability. Tokenize cards via a payment gateway and store the token.
How do I handle failed or timed-out payments?
Record the transaction locally before initiating payment. After user confirms, query the server for status (idempotent) rather than retrying. Never re-charge without confirming the payment failed server-side.