Payment deep links route users directly to a specific payment flow in your fintech or banking app: send money to a recipient, pay a bill, split an expense, or complete a pending transaction. Instead of opening the app and navigating through menus, the user taps one link and lands on the payment screen with details pre-filled.
For the broader fintech deep linking approach, see Deep Linking for Fintech and Banking Apps. For P2P-specific patterns, see P2P Transfer Deep Links.
Photo by Leeloo The First on Pexels
Types of Payment Deep Links
Request Money
A user generates a payment request link that they share with the payer:
https://go.yourapp.com/pay/request?to=user_jane&amount=25.00¬e=Lunch
When the payer taps this link:
- App opens to a "Send Payment" screen
- Recipient is pre-filled (Jane)
- Amount is pre-filled ($25.00)
- Note is pre-filled ("Lunch")
- User confirms and sends
Bill Payment
A biller sends a deep link for payment:
https://go.yourapp.com/pay/bill?biller=ELECTRIC_CO&account=1234567890&amount=142.50&due=2026-05-15
The link pre-fills the bill payment form with the correct biller, account, amount, and due date.
Invoice Payment
For business invoices:
https://go.yourapp.com/pay/invoice/INV-2026-0042?amount=500.00
Split Payment
For splitting expenses among friends:
https://go.yourapp.com/split/SPLIT-ABC?your_share=18.75¬e=Dinner+at+Sushi+Place
Pending Transaction Completion
When a transaction requires additional action (e.g., 2FA confirmation):
https://go.yourapp.com/transactions/TXN-12345/confirm
Implementation
URL Design
Keep payment deep links clean and human-readable:
Base: https://go.yourapp.com/pay
Request: /pay/request?to={recipient}&amount={amount}¬e={note}
Bill: /pay/bill?biller={code}&amount={amount}
Invoice: /pay/invoice/{id}
Split: /split/{id}
App-Side Handler
function handlePaymentDeepLink(url) {
const parsed = new URL(url);
const path = parsed.pathname;
const params = Object.fromEntries(parsed.searchParams);
// Require authentication first
if (user.isAuthenticated === false) {
pendingDeepLink.save(url);
navigation.navigate('Login');
return;
}
if (path.startsWith('/pay/request')) {
navigation.navigate('SendPayment', {
recipient: params.to,
amount: parseFloat(params.amount),
note: params.note,
});
} else if (path.startsWith('/pay/bill')) {
navigation.navigate('BillPayment', {
billerCode: params.biller,
accountNumber: params.account,
amount: parseFloat(params.amount),
dueDate: params.due,
});
} else if (path.startsWith('/pay/invoice')) {
const invoiceId = path.split('/').pop();
navigation.navigate('InvoicePayment', { invoiceId });
} else if (path.startsWith('/split/')) {
const splitId = path.split('/').pop();
navigation.navigate('SplitPayment', { splitId });
}
}
Security Requirements
Payment deep links handle money. Security is non-negotiable.
Authentication Before Payment
Never execute a payment from a deep link without authentication. The deep link pre-fills the payment form, but the user must:
- Be authenticated (biometrics, PIN, or password)
- Review the payment details
- Explicitly confirm the transaction
// Always require auth before showing payment screen
if (user.isAuthenticated === false) {
// Save deep link for after auth
storage.set('pending_payment_link', url);
navigation.navigate('BiometricAuth');
return;
}
Input Validation
Never trust data from the URL. Validate every parameter:
function validatePaymentParams(params) {
// Amount validation
const amount = parseFloat(params.amount);
if (isNaN(amount) || amount <= 0 || amount > MAX_TRANSACTION_AMOUNT) {
throw new Error('Invalid amount');
}
// Recipient validation
if (params.to && isValidRecipient(params.to) === false) {
throw new Error('Invalid recipient');
}
// Biller validation
if (params.biller && isRegisteredBiller(params.biller) === false) {
throw new Error('Unknown biller');
}
return { amount, recipient: params.to, biller: params.biller };
}
Rate Limiting
Prevent abuse by rate-limiting payment deep link processing:
- Maximum 10 payment deep links per user per hour
- Log all payment deep link attempts for audit
Signed URLs
For high-security payment links (invoices, bill pay from billers), use signed URLs:
https://go.yourapp.com/pay/invoice/INV-2026-0042?sig=hmac_sha256_signature&exp=1717027200
The app verifies:
- The signature matches the URL parameters (using a shared secret)
- The expiration timestamp hasn't passed
This prevents tampering (changing the amount or recipient) and replay attacks.
HTTPS Only
Payment deep links must use HTTPS Universal Links/App Links. Never use custom URL schemes (yourapp://pay/...) for payment flows because:
- Custom schemes can be hijacked by malicious apps
- Custom schemes don't verify domain ownership
- Custom schemes aren't encrypted in transit
For deep link security best practices, see Deep Linking Security: Preventing Hijacking and Abuse.
User Experience Patterns
Confirmation Screen
Always show a confirmation screen before processing the payment:
╔═══════════════════════════════════╗
║ Send Payment ║
║ ║
║ To: Jane Smith ║
║ Amount: $25.00 ║
║ Note: Lunch ║
║ ║
║ [Cancel] [Confirm & Send] ║
╚═══════════════════════════════════╝
The user must explicitly tap "Confirm & Send." The deep link populates the form; the user authorizes the action.
Editable Pre-Fill
Let users modify pre-filled values. The recipient might want to change the amount or add a different note:
<PaymentForm
initialRecipient={deepLinkData.recipient}
initialAmount={deepLinkData.amount}
initialNote={deepLinkData.note}
editable={true}
/>
Error States
Handle these gracefully:
- Insufficient funds: Show balance and amount, offer to fund the account
- Unknown recipient: Show "We couldn't find this person. Check the details."
- Expired link: Show "This payment request has expired."
- Already paid: Show "This payment was already completed."
Distribution Patterns
QR Code at Point of Sale
A merchant displays a QR code that deep links to a payment screen:
https://go.yourapp.com/pay/merchant/MERCH-001?amount=42.50&ref=TXN-789
The customer scans, sees "Pay $42.50 to Coffee Shop," and confirms.
Invoice Email
<a href="https://go.yourapp.com/pay/invoice/INV-2026-0042?amount=500&sig=...">
Pay $500.00 →
</a>
Chat Message
Users share payment request links in messaging apps:
"You owe me $18.75 for dinner! Here's my payment link:
https://go.yourapp.com/pay/request?to=jane&amount=18.75¬e=Dinner"
Measuring Performance
| Metric | What It Measures |
|---|---|
| Deep link to auth rate | % of payment link opens that authenticate |
| Auth to confirmation rate | % of authenticated sessions that reach confirmation |
| Confirmation to completion rate | % of confirmations that successfully transact |
| Average transaction value | Mean payment amount from deep links |
| Error rate | % of payment deep links that result in errors |
| Time to complete | Seconds from link tap to transaction confirmed |
For deep linking features, see Tolinku deep linking. For passing data through links, see Deep Link Parameters.
Get deep linking tips in your inbox
One email per week. No spam.