Livedemo
Every wire format, every option — playground for the full public API. Runs in your browser.
The demo below imports thai-qr-payment straight from this site’s bundle and renders the SVG on every keystroke. Drop a PromptPay phone number into the form, set an amount, and scan with your banking app.
EMVCo wire payload (98 chars)
00020101021229370016A000000677010111011300668123456785303764540550.005802TH5911Acme Coffee63048A44Parsed
{
"payloadFormat": "01",
"pointOfInitiation": "dynamic",
"merchant": {
"kind": "promptpay",
"recipientType": "mobile",
"recipient": "0812345678"
},
"amount": 50,
"currency": "764",
"country": "TH",
"merchantName": "Acme Coffee",
"crc": {
"value": "8A44",
"valid": true,
"truncated": false
},
"rawTags": [
{
"tag": "00",
"value": "01"
},
{
"tag": "01",
"value": "12"
},
{
"tag": "29",
"value": "0016A00000067701011101130066812345678"
},
{
"tag": "53",
"value": "764"
},
{
"tag": "54",
"value": "50.00"
},
{
"tag": "58",
"value": "TH"
},
{
"tag": "59",
"value": "Acme Coffee"
},
{
"tag": "63",
"value": "8A44"
}
]
}What just happened
Section titled “What just happened”payloadFor()built the EMVCo MPM wire string from your inputsparsePayload()round-tripped it to verify the CRC + decode the merchant templateencodeQR()ran ISO/IEC 18004 Reed-Solomon ECC + mask selectionrenderThaiQRPayment()composed the final SVG (card mode) orrenderThaiQRPaymentMatrix()emitted just the QR matrix
Every step ran client-side. No network call, no server. Same code-path a production app takes.
Known limitations of the demo
Section titled “Known limitations of the demo”- The dummy phone
0812345678is not a real PromptPay account — your banking app will scan it correctly but reject the recipient at the “confirm” step. - The card mode embeds the Thai QR Payment + PromptPay marks. Production apps must comply with the official brand guidelines when using these logos.