The international data encoding standard used by EMVCo for payment QR codes (Pix, UPI, SGQR, Raast, PromptPay), using nested Tag-Length-Value data objects.
EMVCo Tag-Length-Value encoding is the structural backbone of virtually every modern national instant payment QR code system — from Brazil's Pix to India's UPI, Singapore's SGQR, Pakistan's Raast, and Thailand's PromptPay. Understanding TLV encoding is essential for any developer, payment integrator, or FinTech engineer building QR-based payment products.
The TLV Data Model
In EMVCo's Merchant-Presented QR Code Specification (MPM), each piece of payment data is encoded as a data object consisting of three components:
- Tag (ID): A two-digit ASCII decimal string identifying the data field. Tags range from "00" to "99".
- Length: A two-digit ASCII decimal string indicating the number of characters in the Value field.
- Value: The actual data content, exactly the number of characters specified in Length.
For example, the Payload Format Indicator tag:
- Tag: "00"
- Length: "02" (2 characters)
- Value: "01"
- Complete data object: "000201"
This compact encoding produces human-readable ASCII strings that are simultaneously machine-parseable without a schema lookup table — the length field tells the parser exactly where each value ends.
Nested Data Objects
EMVCo TLV supports hierarchical nesting through merchant account information tags (26 through 51). A payment network registers its sub-tags within a parent tag. For example, Brazil's Pix uses Tag 26 for merchant account information, with sub-tags for the GUI ("br.gov.bcb.pix") and the Pix key.
A minimal Pix static QR payload structure: 00020126 (Payload Format Indicator = 01) 26 (Merchant Account Information, variable length) 0014br.gov.bcb.pix (GUI sub-tag) 0115financeiro@empresa.com.br (Key sub-tag) 5204 (MCC) 5303986 (Currency, 986 = BRL) 54XX (Amount, optional) 5802BR (Country code) 59XX (Merchant name) 60XX (City) 62XX (Additional data field template) 6304XXXX (CRC-16/CCITT checksum, mandatory last field)
The CRC-16/CCITT Checksum (Tag 63)
Every EMVCo payment QR code must end with a 4-character hexadecimal CRC-16/CCITT checksum computed over the entire payload string up to and including "6304". This checksum uses:
- Polynomial: 0x1021
- Initial value: 0xFFFF
- Input/output reflection: none
The CRC provides tamper detection — any modification to the payment amount, merchant name, or Pix key invalidates the checksum and causes banking apps to reject the code.
Why Not Just Use JSON?
TLV encoding was chosen over JSON for payment QR codes because:
- It is more compact (no quotes, brackets, or key names)
- It supports fixed-width parsing without a full JSON parser
- It aligns with ISO 7816 smart card standards already embedded in payment terminal firmware
- It naturally supports forward compatibility — unknown tags are skipped rather than causing parse failures
Diagram description: Annotated EMVCo TLV payload breakdown for a Pix QR code, with each Tag-Length-Value triplet color-coded and labeled with field name, showing the nested merchant account information structure.
