Parse, modify, and output Malaysia DuitNow QR code strings for POS and invoicing integration.
Built on the EMVCo QR Code Specification — the same standard behind Singapore PayNow, Thailand PromptPay, and other national QR payment schemes.
Developed by DH Certainty — the team behind PaynowQR for Singapore.
Have any questions or need help with a custom implementation? Drop us an email at partnerships@dhcertainty.com.
Your bank (Maybank, CIMB, RHB, etc.) generates a static DuitNow QR for your business — but it has no fixed amount. Customers have to key in the amount manually, which is error-prone.
DuitNowQR lets you take that bank-generated QR string and programmatically set the amount, reference number, and other fields — perfect for:
- 🧾 Invoicing systems — generate a QR per invoice with the exact amount
- 🏪 POS terminals — embed the QR with the cart total
- 🔁 Recurring payments — set different amounts per billing cycle
npm install duitnowqrimport { DuitNowQR } from 'duitnowqr';
// 1. Paste the QR string from your bank-generated QR code
const bankQR = '00020201021126580014A000000615000101065887340212MBBQR1872379031000000000005204581253034585802MY5921MORLIVLY WELLNESS PLT6008SELANGOR63042CDE';
// 2. Parse it
const qr = new DuitNowQR(bankQR);
// 3. Set an amount → outputs a new QR string ready for QR code generation
const qrString = qr.setAmount(25.50).toString();
// → '00020201021226580014A0000006150001...540525.50...630445B4'
// Pass this string to any QR code generator (e.g. `qrcode` npm package)- Open your Malaysian banking app (MAE by Maybank, CIMB Clicks, etc.)
- Navigate to your DuitNow QR merchant code
- Take a screenshot or scan the QR code
- Use any QR code reader to extract the raw string — it starts with
000202 - Use that string as the input to
new DuitNowQR(string)
Parse a raw EMVCo QR string into a modifiable object.
const qr = new DuitNowQR('000202010211265800...');Set the transaction amount. Automatically toggles between static and dynamic QR:
| Input | Behaviour |
|---|---|
Positive number (50, 25.50) |
Sets amount, switches to dynamic QR |
Numeric string ('100') |
Sets amount, switches to dynamic QR |
Falsey (null, undefined, 0, '', false) |
Removes amount, switches to static QR |
qr.setAmount(50); // RM 50.00, dynamic QR
qr.setAmount('25.50'); // RM 25.50, dynamic QR
qr.setAmount(null); // no amount, static QR
qr.setAmount(0); // no amount, static QRSet the merchant name (max 25 characters).
Set the merchant city (max 15 characters).
Set the 4-digit Merchant Category Code.
Set a bill/reference number (stored in Tag 62). Pass null to remove.
Set the postal code. Pass null to remove.
Rebuild the full QR string with a recalculated CRC checksum. Pass this to a QR code generator.
const qrString = qr.setAmount(50).toString();Get a structured, human-readable object of all parsed fields.
const data = qr.toJSON();
// {
// payloadFormatIndicator: '02',
// pointOfInitiationType: 'dynamic',
// merchantAccountInfo: {
// guid: 'A0000006150001',
// acquirerId: '588734',
// merchantAccountNumber: 'MBBQR1872379',
// ...
// },
// transactionAmount: '50.00',
// merchantName: 'MORLIVLY WELLNESS PLT',
// ...
// }| Getter | Description |
|---|---|
.payloadFormatIndicator |
'02' for DuitNow |
.pointOfInitiation |
'11' (static) or '12' (dynamic) |
.isStatic |
true if no fixed amount |
.guid |
DuitNow AID (A0000006150001) |
.acquirerId |
Bank/switching institution ID |
.merchantAccountNumber |
Merchant account (e.g. MBBQR1872379) |
.merchantCategoryCode |
4-digit MCC |
.transactionCurrency |
'458' for MYR |
.amount |
Amount string or null if static |
.countryCode |
'MY' |
.merchantName |
Business name |
.merchantCity |
City |
.postalCode |
Postal code or null |
.referenceNumber |
Bill/reference number or null |
import { DuitNowQR } from 'duitnowqr';
import QRCode from 'qrcode';
const BASE_QR = '00020201021126580014A0000006150001...63042CDE';
async function generatePaymentQR(cartTotal: number, orderId: string) {
const qrString = new DuitNowQR(BASE_QR)
.setAmount(cartTotal)
.setReferenceNumber(orderId)
.toString();
// Generate QR image (using 'qrcode' npm package)
const dataUrl = await QRCode.toDataURL(qrString);
return dataUrl;
}
// Usage
const qrImage = await generatePaymentQR(45.90, 'ORD-20240304-001');import { DuitNowQR } from 'duitnowqr';
const BASE_QR = '00020201021126580014A0000006150001...63042CDE';
function generateInvoiceQR(invoiceNumber: string, amount: number) {
return new DuitNowQR(BASE_QR)
.setAmount(amount)
.setReferenceNumber(invoiceNumber)
.toString();
}
// Generate QR strings for multiple invoices
const invoices = [
{ id: 'INV-001', amount: 150.00 },
{ id: 'INV-002', amount: 89.90 },
{ id: 'INV-003', amount: 320.00 },
];
for (const inv of invoices) {
const qr = generateInvoiceQR(inv.id, inv.amount);
console.log(`${inv.id}: ${qr}`);
}import { DuitNowQR } from 'duitnowqr';
const qr = new DuitNowQR('000202010211265800...');
const data = qr.toJSON();
console.log(`Merchant: ${data.merchantName}`);
console.log(`Bank Account: ${data.merchantAccountInfo.merchantAccountNumber}`);
console.log(`Type: ${data.pointOfInitiationType}`);
console.log(`Amount: ${data.transactionAmount ?? 'Open (customer enters amount)'}`);| Tag | Field | Example Value |
|---|---|---|
| 00 | Payload Format Indicator | 02 |
| 01 | Point of Initiation | 11 (static) / 12 (dynamic) |
| 26 | Merchant Account Info | (nested template) |
| 26.00 | GUID (PayNet AID) | A0000006150001 |
| 26.01 | Acquirer Institution ID | 588734 |
| 26.02 | Merchant Account Number | MBBQR1872379 |
| 26.03 | Reserved Field | 0000000000 |
| 52 | Merchant Category Code | 5812 |
| 53 | Transaction Currency | 458 (MYR) |
| 54 | Transaction Amount | 50.00 |
| 58 | Country Code | MY |
| 59 | Merchant Name | MORLIVLY WELLNESS PLT |
| 60 | Merchant City | SELANGOR |
| 62.01 | Reference / Bill Number | INV-001 |
| 63 | CRC Checksum | 2CDE |
DuitNowQR is developed and maintained by DH Certainty, a fintech solutions company specialising in payment integrations across Southeast Asia.
Other projects by DH Certainty:
- PaynowQR — Singapore PayNow QR code generator for Node.js and JavaScript
- XeroPayNowQR — Xero invoicing integration with PayNow QR
Feel free to report any issues and feature requests!
MIT