EMVCo merchant QR
The EMVCo QR Code Specification is the TLV-encoded format that sits underneath most national mobile-payment schemes — PIX (Brazil), PromptPay (Thailand), UPI (India), SGQR (Singapore), DuitNow (Malaysia), BPS PayNow (Singapore), and many others. Understanding the EMVCo base format means understanding a dozen regional derivatives at once.
Merchant Presented vs Consumer Presented
- MPM (Merchant Presented Mode). Static or dynamic QR displayed by the merchant. Consumer scans it from their banking/wallet app and authorises the payment. 99% of real-world QR payments use MPM.
- CPM (Consumer Presented Mode). Consumer's app generates a short-lived QR (typically 30–60 seconds); merchant scans it. Less common; used where consumer connectivity is unreliable (rural India pre-UPI ubiquity, some MRT/transit systems).
MPM structure
MPM payload is a flat sequence of TLV records terminated by a CRC:
| Tag | Name | Length | Notes |
|---|
00 | Payload format indicator | 2 | Always 01. |
01 | Point of initiation method | 2 | 11 static / 12 dynamic. |
02–51 | Merchant account information | variable | Scheme-specific. Each scheme reserves its own tag: PIX uses 26, UPI uses 26 too, SGQR uses 51. |
52 | Merchant Category Code (MCC) | 4 | ISO 18245 4-digit code. See table below. |
53 | Transaction currency | 3 | ISO 4217 numeric. 840=USD, 978=EUR, 356=INR, 986=BRL, 764=THB. |
54 | Transaction amount | variable | Decimal as string. Omit for static amount-at-scan QRs. |
58 | Country code | 2 | ISO 3166 alpha-2. |
59 | Merchant name | variable | Max 25 chars per spec; many schemes relax this. |
60 | Merchant city | variable | Max 15 chars. |
62 | Additional data field template | variable | Bill reference, loyalty, terminal ID. |
63 | CRC | 4 | CRC16-CCITT over everything before this tag (including the tag itself, length 04, minus the 4-digit value). |
Regional schemes that derive from EMVCo
| Scheme | Country | Merchant account tag | Notes |
|---|
| PIX | Brazil | 26 | Brazilian Central Bank instant-payment scheme. Adds CPF/CNPJ/email/phone PIX keys as sub-TLVs under tag 26. |
| PromptPay | Thailand | 29 / 30 | Uses 29 for national ID / tax ID and 30 for mobile number. |
| UPI | India | 26 | Same EMVCo base with UPI-specific sub-TLVs (VPA, payee name). |
| SGQR | Singapore | 51 | Unified QR that encodes multiple payment rails (PayNow, NETS, UOB Pay) simultaneously. |
| DuitNow | Malaysia | 27 | PayNet's national instant payment scheme. |
| FPS | Hong Kong | 27 | Faster Payment System by HKICL. |
| JPQR | Japan | 50 | METI-backed unified Japanese QR standard. |
Common MCC codes
| MCC | Merchant category |
|---|
5411 | Grocery stores, supermarkets |
5812 | Eating places, restaurants |
5814 | Fast-food restaurants |
5999 | Miscellaneous retail |
7230 | Beauty / barber shops |
8011 | Doctors |
8398 | Charitable / social service organisations |
0000 | Unknown / placeholder (spec allows this) |
Canonical test vectors
| Case | Inputs | Expected TLV head |
|---|
| Static MPM, USD, no amount | merchant=Acme Corp city=LAS VEGAS country=US currency=840 mcc=5999 | 00020101021152045999...53037405802US5909Acme Corp6009LAS VEGAS |
| Dynamic MPM, EUR, amount 25.00 | (same)
amount=25.00 | Starts 000201010212 (POI method 12 = dynamic), includes 540525.00. |
| Restaurant bill, INR 250, MCC 5812 | merchant=Spice House city=MUMBAI country=IN currency=356 mcc=5812 amount=250 | MCC field: 52045812. Currency: 5303356. |
Common pitfalls
- CRC computed wrong. The CRC16-CCITT is over the ENTIRE payload including tag
63 and length 04 — everything up to but not including the 4-digit CRC value. Most bugs come from computing over the payload only or including the CRC value itself. - Length field is 2 digits. Even a 1-character value takes length
01. A 100-character value takes length ?? — but wait, EMVCo caps values at 99 chars because length is 2 digits. Longer values need to be split across multiple sub-TLVs. - Currency code is numeric, not alpha. USD is
840, not USD. EUR is 978. BRL is 986. ISO 4217 has both alpha-3 and numeric; EMVCo requires numeric. - Country code is alpha-2. US, IN, BR, TH. ISO 3166-1 alpha-2. Confusingly opposite to the currency-code rule.
- Static vs dynamic. If you omit the amount (tag
54), use POI method 11 (static). Static QR + amount field is spec-legal but some apps reject it. Dynamic QR without amount is a spec violation. - Merchant name char limit. Per spec, 25 chars max. Some regional schemes relax this (PIX allows 25, SGQR allows 40). Hand-tune per scheme if you're targeting a specific country.
- MCC
0000. The spec permits 0000 as unknown — but many acquirers reject it in settlement. Always prefer a real MCC when you have one.
Scanner compatibility
| App / device | Support | Notes |
|---|
| Banking / wallet app | Native | Regional apps in each country (Nubank / UPI apps / TrueMoney / GrabPay) parse the EMVCo payload natively. |
| iOS Camera | Raw string | Not recognised as payment. User must open their banking app and scan from there. |
| Android Camera | Raw string | Same — not parsed. |
| Google Lens | Raw string | Displays decoded text. |
| Industrial payment terminals | Native | Modern POS scanners include EMVCo parsing in firmware for the regional scheme(s) they support. |
See also
Spec version verified 2026-04-18 (EMVCo MPM v1.1 / CPM v1.1). Next review: 2026-07-18.