@nds-stack/qris-utils
v1.0.0
Published
QRIS utilities - decode, parse, convert, and validate Indonesian QRIS payment codes
Maintainers
Readme
@nds-stack/qris-utils
QRIS utilities for Node.js - decode, parse, convert, and validate Indonesian QRIS payment codes.
✨ Features
- 📷 QR Decoder - Extract QRIS string from images (base64, buffer, file, URL)
- 🔍 TLV Parser - Parse QRIS TLV structure to readable object
- 🔄 Static → Dynamic Converter - Convert static QRIS to dynamic with amount
- ✅ CRC16 Validator - Validate QRIS checksum
- 📝 TypeScript Ready - Full type definitions included
- 🚀 Zero Config - Works out of the box
📦 Installation
npm install @nds-stack/qris-utils🚀 Quick Start
const qris = require('@nds-stack/qris-utils');
// If you already have a QRIS string
const qrisString = '00020101021126650013ID...';
// Parse QRIS string
const parsed = qris.parseQRIS(qrisString);
console.log(parsed.merchantName); // "Warung Sayur"
console.log(parsed.method); // "static"
// Convert static to dynamic (Rp 50.000)
const dynamicQRIS = qris.convertQRIS(qrisString, { amount: 50000 });
// Validate QRIS
const isValid = qris.validateCRC16(dynamicQRIS);📚 API Reference
CRC16
| Method | Description |
|--------|-------------|
| calculateCRC16(str) | Calculate CRC16-CCITT checksum |
| validateCRC16(qrisString) | Validate QRIS string CRC |
Parser
| Method | Description |
|--------|-------------|
| parseTLV(data) | Parse raw TLV string to elements |
| parseQRIS(qrisString) | Parse QRIS string to structured object |
Converter
| Method | Description |
|--------|-------------|
| convertQRIS(qrisString, { amount }) | Convert static → dynamic QRIS |
| convertQRISWithFee(qrisString, { amount, fee }) | Convert with service fee |
Decoder
| Method | Description |
|--------|-------------|
| decodeQRFromBase64(base64Image) | Decode QR from base64 string |
| decodeQRFromBuffer(imageBuffer) | Decode QR from Buffer |
| decodeQRFromFile(filePath) | Decode QR from local file |
| decodeQRFromUrl(imageUrl, fetchOptions) | Download & decode QR from URL |
| isValidQRISString(str) | Check if string is valid QRIS |
Generator
| Method | Description |
|--------|-------------|
| generateQRDataURL(qrisString, options) | Generate QR as data URL (base64 image) |
| generateQRBuffer(qrisString, options) | Generate QR as Buffer (PNG) |
| generateQRBase64(qrisString, options) | Generate QR as base64 string |
| generateQRFile(qrisString, filePath, options) | Save QR to file |
| generateQRSVG(qrisString, options) | Generate QR as SVG string |
| generateQRAscii(qrisString, options) | Generate QR as ASCII/terminal output |
📖 Examples
Parse QRIS String
const qris = require('@nds-stack/qris-utils');
const qrisString = '00020101021126650013ID...';
const parsed = qris.parseQRIS(qrisString);
console.log('Merchant:', parsed.merchantName);
console.log('City:', parsed.merchantCity);
console.log('MCC:', parsed.merchantCategoryCode);
console.log('Method:', parsed.method);Decode QRIS from Local File
const qris = require('@nds-stack/qris-utils');
const qrisString = await qris.decodeQRFromFile('./qris-static.png');
console.log('QRIS String:', qrisString);Decode QRIS from URL
const qris = require('@nds-stack/qris-utils');
const qrisString = await qris.decodeQRFromUrl('https://example.com/qris.png', {
headers: { 'Authorization': 'Bearer token' } // optional
});Decode QRIS from Base64
const qris = require('@nds-stack/qris-utils');
const base64Image = 'data:image/png;base64,iVBORw0KGgo...';
const qrisString = await qris.decodeQRFromBase64(base64Image);Decode QRIS from Buffer
const qris = require('@nds-stack/qris-utils');
const fs = require('fs');
const buffer = fs.readFileSync('./qris.png');
const qrisString = await qris.decodeQRFromBuffer(buffer);Convert Static to Dynamic QRIS
const qris = require('@nds-stack/qris-utils');
const staticQRIS = '00020101021126650013ID...';
const dynamicQRIS = qris.convertQRIS(staticQRIS, { amount: 50000 });
console.log('Dynamic QRIS:', dynamicQRIS);Convert with Service Fee
const qris = require('@nds-stack/qris-utils');
const staticQRIS = '00020101021126650013ID...';
// Fixed fee Rp 1.000
const withFixedFee = qris.convertQRISWithFee(staticQRIS, {
amount: 50000,
fee: { type: 'fixed', value: 1000 }
});
// Percentage fee 2.5%
const withPercentFee = qris.convertQRISWithFee(staticQRIS, {
amount: 50000,
fee: { type: 'percentage', value: 2.5 }
});Generate QR Image
const qris = require('@nds-stack/qris-utils');
const qrisString = '000201010212...';
// Generate as data URL (bisa langsung tampil di browser)
const dataUrl = await qris.generateQRDataURL(qrisString);
// Save to file
await qris.generateQRFile(qrisString, './qris-dynamic.png');
// Generate base64
const base64 = await qris.generateQRBase64(qrisString);Full Flow: From Image to Dynamic QRIS (Complete)
const qris = require('@nds-stack/qris-utils');
// Step 1: Decode QR from image file
const staticQRIS = await qris.decodeQRFromFile('./qris-static.png');
// Step 2: Parse to see merchant info (optional)
const parsed = qris.parseQRIS(staticQRIS);
console.log('Merchant:', parsed.merchantName);
console.log('Original method:', parsed.method);
// Step 3: Convert static to dynamic with amount
const amount = 75000;
const dynamicQRIS = qris.convertQRIS(staticQRIS, { amount });
// Step 4: Validate the dynamic QRIS
if (qris.validateCRC16(dynamicQRIS)) {
console.log('✅ Dynamic QRIS is valid!');
} else {
console.log('❌ Invalid QRIS!');
}
// Step 5: Generate QR image from dynamic QRIS
// Option A: Save to file
await qris.generateQRFile(dynamicQRIS, './qris-dynamic.png');
console.log('✅ QR saved to qris-dynamic.png');
// Option B: Get as data URL (for web display)
const dataUrl = await qris.generateQRDataURL(dynamicQRIS);
console.log('✅ QR data URL ready');
// Option C: Get as base64 (for API response)
const base64 = await qris.generateQRBase64(dynamicQRIS);
console.log('✅ QR base64 ready');
// Step 6: Ready to be scanned and paid!
console.log(`📱 Scan the QR to pay Rp ${amount.toLocaleString('id-ID')}`);🔧 Requirements
- Node.js >= 18.0.0
📄 License
MIT © nds-stack
⚠️ Disclaimer
This project is for educational purposes only. Use at your own risk.
