developer
How to Build a Dynamic UPI QR Generator in Node.js and Express (Full Source Code)
Build a dynamic UPI QR code generator in Node.js & Express. Learn the NPCI upi://pay URI spec, Base64 QR encoding, order metadata binding, and webhook handling.
Generating dynamic, order-linked Unified Payments Interface (UPI) QR codes on the fly is one of the most powerful capabilities for modern Indian web applications. Instead of forcing customers to type an amount on a faded counter sticker, your server generates a unique barcode containing the exact invoice figure and order reference.
Here is the complete, production-ready tutorial to building a dynamic UPI QR generator using Node.js, Express, and standard open-source libraries.
Understanding the NPCI UPI URI Specification
Direct Answer: An automated UPI QR code is simply a standard 2D barcode encoding a URI string compliant with the NPCI UPI Linking Specification. The protocol starts with
upi://pay?followed by mandatory query parameters specifying the payee VPA (pa), payee trade name (pn), transaction reference (tr), payment amount (am), and currency code (cu=INR).
The Official NPCI Key-Value Parameters:
| Parameter | Key Name | Mandatory | Description & Example |
|---|---|---|---|
pa | Payee Address | Yes | Merchant Virtual Payment Address (billing@hdfcbank) |
pn | Payee Name | Yes | Business or legal trade name (Acme Retail Private Limited) |
tr | Transaction Ref | Yes | Unique merchant order/invoice ID (ORD_9482103) |
am | Amount | Optional (Mandatory for Dynamic) | Decimal transaction value (1499.00) |
cu | Currency Code | Yes | Currency code (INR) |
mc | Merchant Category | Recommended | 4-digit MCC code (5411 for grocery, 5812 for dining) |
tn | Transaction Note | Optional | Short memo displayed to customer (Order 94821 Checkout) |
Setting Up the Node.js & Express Project
Initialize a clean project and install the essential dependencies:
mkdir upi-qr-service && cd upi-qr-service
npm init -y
npm install express qrcode dotenv cors
npm install --save-dev nodemon
Complete Backend Source Code (server.js)
Create server.js with structured input validation and Base64 Data URL rendering:
import express from 'express';
import QRCode from 'qrcode';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
app.use(express.json());
app.use(cors());
const MERCHANT_VPA = process.env.MERCHANT_VPA || 'vyapargateway@hdfcbank';
const MERCHANT_NAME = process.env.MERCHANT_NAME || 'Vyapar Store';
/**
* Builds compliant NPCI UPI payment string
*/
function buildUpiString({ vpa, name, txnId, amount, note, mcc = '5411' }) {
const params = new URLSearchParams({
pa: vpa,
pn: name,
tr: txnId,
am: Number(amount).toFixed(2),
cu: 'INR',
mc: mcc,
tn: note || `Order ${txnId}`,
});
return `upi://pay?${params.toString()}`;
}
/**
* POST /api/generate-qr
* Generates Base64 QR code and raw intent link
*/
app.post('/api/generate-qr', async (req, res) => {
try {
const { orderId, amount, note } = req.body;
if (!orderId || !amount || Number(amount) <= 0) {
return res.status(400).json({
success: false,
error: 'Valid orderId and positive amount are required.',
});
}
const upiString = buildUpiString({
vpa: MERCHANT_VPA,
name: MERCHANT_NAME,
txnId: orderId,
amount: amount,
note: note,
});
// Generate high-resolution Base64 PNG QR code
const qrDataUrl = await QRCode.toDataURL(upiString, {
errorCorrectionLevel: 'M',
margin: 2,
width: 400,
color: {
dark: '#0F172A',
light: '#FFFFFF',
},
});
return res.status(200).json({
success: true,
orderId,
amount: Number(amount).toFixed(2),
upiString,
qrDataUrl,
});
} catch (error) {
console.error('QR Generation Failed:', error);
return res.status(500).json({ success: false, error: 'Internal Server Error' });
}
});
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`UPI QR Service running on http://localhost:${PORT}`);
});
Serving Dynamic QR Codes to the Frontend
On your frontend (React, Vue, or vanilla HTML/JS), consume the endpoint and display the payment interface:
<div class="checkout-card">
<h3>Scan to Pay via ANY UPI App</h3>
<img id="qr-image" src="" alt="UPI Dynamic QR Code" width="300" height="300" />
<p>Amount: ₹<span id="order-amount">1,499.00</span></p>
<!-- Mobile Intent Button for 1-Tap Checkout -->
<a id="intent-btn" href="#" class="btn-upi">
Pay on Mobile (GPay / PhonePe / Paytm)
</a>
</div>
<script>
async function loadCheckout(orderId, amount) {
const response = await fetch('/api/generate-qr', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orderId, amount, note: 'T-Shirt Order' })
});
const data = await response.json();
if (data.success) {
document.getElementById('qr-image').src = data.qrDataUrl;
document.getElementById('intent-btn').href = data.upiString;
}
}
loadCheckout('ORD_9942', 1499.00);
</script>
Production Best Practices and Security
- Strict Expiry TTLs: Dynamic QR codes should expire after 10 to 15 minutes to prevent stale payments.
- Never Trust Frontend Status: Never fulfill an order simply because the user claims they paid. Always verify the incoming payment via backend bank webhooks or an automated provider API like VyaparGateway.
- Use Vector SVG for Print Receipts: For POS thermal printers, generate SVG instead of PNG using
QRCode.toString(upiString, { type: 'svg' })to guarantee crisp barcode scannability.
Try generating live test intent strings instantly with our UPI Intent Link Generator.
Direct answers
Frequently asked questions
- What is the official NPCI UPI URI string format for dynamic QR codes?
- The official NPCI URI format is: upi://pay?pa=MERCHANT_VPA&pn=MERCHANT_NAME&tr=TRANSACTION_REF&am=AMOUNT&cu=INR&tn=NOTE, where parameters are URL-encoded key-value pairs specifying payee address, order reference, and amount.
- How does a dynamic QR code differ from a static QR code in UPI?
- A static QR contains only the merchant VPA and requires the customer to manually type the payment amount. A dynamic QR embeds the exact transaction amount and order ID, preventing customer typing mistakes and enabling automated order reconciliation.
- Which Node.js library is best for generating UPI QR codes?
- The qrcode npm package is the industry standard in Node.js for generating fast, dependency-free SVG, PNG, and Base64 Data URL QR code images on the server.
Build your payment flow
Explore the API and browser-only merchant tools.
Create UPI checkout orders, verify signed events, or test the free calculators and generators without exposing credentials.