TypeScript library for generating KHQR codes (Cambodia's national payment QR standard)
bakong-khqr is a TypeScript/JavaScript library for generating KHQR codes, Cambodia's national QR payment standard used by the Bakong payment system operated by the National Bank of Cambodia.
This library enables merchants and developers to:
- Generate static and dynamic payment QR codes
- Support both USD and KHR currencies
- Integrate with Bakong's API for deep links and payment verification
- Create styled QR code images
npm install bakong-khqryarn add bakong-khqrpnpm add bakong-khqrimport { KHQR } from "bakong-khqr";
const khqr = new KHQR();
// Dynamic QR with fixed amount
const qrString = khqr.createQR({
bankAccount: "yourname@bank",
merchantName: "Your Shop Name",
merchantCity: "Phnom Penh",
amount: 10.5,
currency: "USD",
});
console.log(qrString);
// Output: 0002010102122915...6304XXXXconst staticQR = khqr.createQR({
bankAccount: "yourname@bank",
merchantName: "Your Shop",
merchantCity: "Siem Reap",
amount: 0, // Zero = static QR
currency: "KHR",
});new KHQR(options?: { bakongToken?: string })| Option | Type | Description |
|---|---|---|
bakongToken |
string |
Bakong Developer Token (required for API features) |
Generate a KHQR code string.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
bankAccount |
string |
✅ | Bakong account (e.g., name@bank) |
merchantName |
string |
✅ | Merchant name (max 25 chars) |
merchantCity |
string |
✅ | City name (max 15 chars) |
amount |
number |
✅ | Transaction amount (0 for static QR) |
currency |
"USD" | "KHR" |
✅ | Currency code |
storeLabel |
string |
❌ | Store/branch label (max 25 chars) |
phoneNumber |
string |
❌ | Merchant phone number |
billNumber |
string |
❌ | Bill/invoice number (max 25 chars) |
terminalLabel |
string |
❌ | Terminal/description (max 25 chars) |
static |
boolean |
❌ | Force static QR (default: false) |
expiration |
number |
❌ | Expiration in days (default: 1) |
Generate MD5 hash of QR string for transaction tracking.
const md5 = khqr.generateMD5(qrString);
// Returns: "64bffcefc9425d2cfd02c9ecf954a132"Requires a Bakong Developer Token.
const khqr = new KHQR({ bakongToken: "your_token" });
// Generate deep link
const deepLink = await khqr.generateDeepLink({
qr: qrString,
callback: "https://yourapp.com/callback",
appIconUrl: "https://yourapp.com/icon.png",
appName: "Your App",
});
// Check payment status
const status = await khqr.checkPayment(md5Hash);
// Returns: "PAID" or "UNPAID"
// Get payment details
const payment = await khqr.getPayment(md5Hash);
// Check multiple payments
const paidList = await khqr.checkBulkPayments([md5_1, md5_2, md5_3]);import { generateQRImage } from "bakong-khqr";
// Generate base64 PNG
const dataURI = await generateQRImage(qrString, "data-uri");
// Returns: "data:image/png;base64,iVBORw0KGgo..."
// Get buffer for saving
const buffer = await generateQRImage(qrString, "buffer");import { KHQR, generateQRImage } from "bakong-khqr";
async function demo() {
const khqr = new KHQR();
// Create a $10.50 USD payment QR
const qr = khqr.createQR({
bankAccount: "john@acleda",
merchantName: "John's Coffee",
merchantCity: "Phnom Penh",
amount: 10.5,
currency: "USD",
storeLabel: "Downtown Branch",
terminalLabel: "Coffee Purchase",
});
console.log("QR Code:", qr);
// Generate MD5 for tracking
const md5 = khqr.generateMD5(qr);
console.log("Tracking Hash:", md5);
// Create QR image
const image = await generateQRImage(qr, "data-uri");
console.log("QR Image (base64):", image.substring(0, 50) + "...");
}
demo();KHQR follows the EMVCo QR Code Specification with Cambodia-specific extensions:
| Tag | Field | Example |
|---|---|---|
| 00 | Payload Format Indicator | 01 |
| 01 | Point of Initiation | 11 (static) / 12 (dynamic) |
| 29 | Merchant Account Information | 0011name@bank |
| 52 | Merchant Category Code | 5999 |
| 53 | Transaction Currency | 840 (USD) / 116 (KHR) |
| 54 | Transaction Amount | 10.50 |
| 58 | Country Code | KH |
| 59 | Merchant Name | John's Coffee |
| 60 | Merchant City | Phnom Penh |
| 62 | Additional Data | Bill number, store label, etc. |
| 63 | CRC | 6304 + 4 hex chars |
| 99 | Timestamp (Bakong-specific) | Creation + expiration time |
Any bank or financial institution on the Bakong network:
- ACLEDA Bank
- Canadia Bank
- ABA Bank
- Sathapana Bank
- And many more...
Account format: username@bankcode
See full API documentation for detailed class and method documentation.
import {
KHQR, // Main class
EMV, // EMV constants
CRC, // CRC-16 calculator
Hash, // MD5 utility
EMVParser, // Parse QR strings
// Field formatters:
Amount,
TimeStamp,
PayloadFormatIndicator,
PointOfInitiation,
GlobalUniqueIdentifier,
MCC,
TransactionCurrency,
CountryCode,
MerchantName,
MerchantCity,
AdditionalDataField,
} from "bakong-khqr";Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
- National Bank of Cambodia for the Bakong payment system
- EMVCo for the QR code specification
Made with ❤️ for the Cambodian developer community