跳到正文
DEV Community· Sourav Mahapatra·· 3 小時前AI 評分44

如何運用 UPI 深層連結(upi://pay)建立付款連結和 QR code,而毋須使用付款閘道

How UPI deep links work (upi://pay): build a payment link and QR code without a payment gateway

AI 導讀

UPI 深層連結可讓用戶透過 upi://pay URL 開啟 UPI 付款應用程式,並預先填入付款資料;開發者可用 JavaScript 建立連結,再轉成 QR code。這類連結只適用於流動裝置,不能確認付款或提供 webhook;需要自動確認、退款、收據或訂閲時,應使用付款閘道。

正文

If you've ever tapped "Pay" on a website in India and watched your phone jump straight into Google Pay, PhonePe, Paytm or BHIM with the amount already filled in, you've used a UPI deep link. It's just a URL that starts with upi://pay, and you can build one yourself in a few lines, with no payment gateway, no merchant account and no API keys.

This post explains what's in that URL, how to generate it safely in JavaScript, how to turn it into a QR code, and, just as important, what it can't do for you.

The URL format

A UPI payment link looks like this:

upi://pay?pa=yourname@okhdfcbank&am=499.00&tn=Logo%20design%20deposit&cu=INR

upi:// is a URI scheme. When a phone opens a link with that scheme, the operating system hands it to an installed app that has registered for it, which means any UPI app. The query parameters come from NPCI's UPI linking specification. The ones you'll actually use:

Parameter Meaning Required?
pa Payee address: the UPI ID (VPA) that receives the money, e.g. name@okicici Yes
pn Payee name, shown to the payer by some apps Often listed as required in the spec, but many apps resolve the name from the VPA anyway
am Amount, in rupees, with up to two decimals No. Leave it out and the payer types the amount
cu Currency. Always INR Recommended
tn Transaction note, e.g. "Invoice 1042" No
tr Transaction reference ID (mainly used by merchants) No

Two practical notes:

  1. Leaving out am is a feature. For tips, donations or "pay what you owe", an open amount is friendlier than a fixed one.
  2. The payer's app shows who they're paying. Before approving, UPI apps typically display the name registered against the VPA. That's your real trust signal, more than anything you put in the link.

Building the link in JavaScript

Don't concatenate strings by hand: a note like Design & dev will break your query string. Let URLSearchParams do the encoding:

function buildUpiLink({ upiId, amount, note }) {
  if (!upiId || !/^[\w.\-]{2,}@[a-zA-Z]{2,}$/.test(upiId.trim())) {
    throw new Error('Enter a valid UPI ID, e.g. name@okhdfcbank');
  }
  const params = new URLSearchParams({ pa: upiId.trim(), cu: 'INR' });
  if (amount) {
    const value = Number(amount);
    if (!(value > 0)) throw new Error('Amount must be a positive number');
    params.set('am', value.toFixed(2));
  }
  if (note) params.set('tn', note.trim().slice(0, 50));
  return `upi://pay?${params.toString()}`;
}

console.log(buildUpiLink({ upiId: 'studio@okaxis', amount: 1500, note: 'Website audit' }));
// upi://pay?pa=studio%40okaxis&cu=INR&am=1500.00&tn=Website+audit

Things worth knowing about that output:

  • URLSearchParams encodes @ as %40 and spaces as +. UPI apps generally decode both. If you see a literal + in the note in a particular app, build the query with encodeURIComponent instead, which gives %20 for spaces.
  • The regex above is a sanity check, not validation. The only way to know a VPA is real is to send a small payment to it. Your code can't verify ownership.
  • Keep notes short. Apps truncate long notes differently, so a 50-character cap is a sensible default.

Turning it into a QR code

A QR code is the same link, drawn as a matrix. The payer scans it with their UPI app's scanner, not the camera app, and gets the same prefilled screen. With the popular qrcode package:

import QRCode from 'qrcode';

const link = buildUpiLink({ upiId: 'studio@okaxis', amount: 1500, note: 'Website audit' });

// In the browser, draw onto a <canvas id="qr">
await QRCode.toCanvas(document.getElementById('qr'), link, {
  errorCorrectionLevel: 'H', // survives smudges and small logos
  width: 240,
  margin: 2,
});

// Or produce a PNG data URL for an invoice PDF
const pngDataUrl = await QRCode.toDataURL(link, { errorCorrectionLevel: 'H' });

Use high error correction (H) if the code will be printed on a counter card or an invoice that might get folded. Then test it with at least two different UPI apps before you print a hundred copies.

Where the link works, and where it doesn't

This is the part most tutorials skip:

  • Mobile only. On a desktop browser, upi:// usually does nothing because no app is registered for it. On desktop, show the QR code and keep the link for mobile.
  • In-app browsers vary. Some email clients and social apps' built-in browsers block custom schemes. If a tap does nothing, open the page in Chrome or Safari, or scan the QR code instead.
  • iOS is less predictable than Android. On Android, the system shows a chooser of UPI apps. iOS behaviour depends on which apps are installed and how they handle the scheme. Test on the devices your payers actually use.
  • Apps may add friction for personal VPAs. Some apps show warnings or limits for link-initiated payments to non-merchant UPI IDs. That's the app protecting the payer, and you can't override it from the link.

What a deep link can't do (read this before using it for a business)

A upi://pay link starts a payment. It doesn't confirm one. There's no callback, no webhook and no "payment succeeded" event in your app. Practically:

  • Reconcile manually. Match incoming credits in your bank or UPI app against the note or amount. A unique note per invoice ("INV-1042") makes this much easier.
  • Depending on the app, a payer may be able to change a prefilled amount, and nothing stops them from paying twice. Treat the link as a convenience, not an enforcement mechanism.
  • For order systems, use a gateway. If you need automatic confirmation, refunds, receipts or subscriptions, use a payment gateway (Razorpay, Cashfree, PayU and others). They issue merchant VPAs and send you webhooks. Deep links are for freelancers, small sellers, event collections and invoices, where a human checks the bank statement anyway.

Good uses

  • Freelance invoices: add the link and QR code to the PDF so a client on their phone can pay in two taps.
  • WhatsApp and email follow-ups: "Here's the link for the ₹1,500 deposit" beats sending your UPI ID and asking them to type it.
  • Events and group collections: one QR code on a poster, with an open amount.
  • Tip jars and donation buttons on a personal site, shown as a QR code on desktop.

Shortcut, if you don't want to write code

I built a free generator that does exactly the steps above in the browser: enter a UPI ID, an optional amount and an optional note, and you get the upi://pay link plus a QR code to copy or save. There's no signup and no gateway in between, and it doesn't add a payee name, so the payer's app shows the name linked to your UPI ID. UPI payment link creator on BeginThings. Disclosure: BeginThings is my project.

Checklist before you share a UPI link

  1. Test the link and the QR code with two different UPI apps.
  2. Check that the payee name the app shows is the one your payer expects.
  3. Use a unique note per invoice so reconciliation takes seconds.
  4. On desktop pages, show the QR code first and the link second.
  5. Don't promise "instant confirmation". A deep link can't give you one.

If you've hit an app-specific quirk with upi://pay links, I'd love to hear which app and what happened, in the comments.

This article was drafted with AI assistance and checked against the generator's source code and NPCI's published parameter names before publishing.

來源:DEV Community · dev.to