Skip to content
CardTools

EMVCo QR Decoder

Decode a merchant-presented QR payload and verify its CRC.

Runs entirely in your browser. Nothing you paste is uploaded, logged or stored.

The decoded text from the QR image, not the image itself
Try:
Paste the text a QR scanner produced. This decodes the payload; it does not read images.

CRC calculator

CRC-16/CCITT-FALSE, the algorithm EMVCo QR uses

Polynomial 0x1021, initial value 0xFFFF, no reflection, no final XOR. The string 123456789 should give 29B1.

The encoding

EMVCo merchant-presented QR is ID-Length-Value: every element is a 2-digit ASCII identifier, a 2-digit ASCII length, then exactly that many characters of value. It resembles BER-TLV but is simpler: no multi-byte tags, no long-form lengths, and everything is printable ASCII, so a payload is human-readable if you know where the boundaries fall.

Some elements are templates whose values contain more ID-Length-Value elements: the merchant account information range (26-51), the additional data template (62), and the language template (64).

Lengths count characters, not bytes

EMVCo defines a length as the number of characters in the value. For an ASCII payload that is also the number of bytes, so the distinction never comes up, and most payloads are ASCII: PIX asks for merchant names without accents partly for this reason.

It comes up the moment a value carries one. CAFÉ CENTRAL is twelve characters and thirteen UTF-8 bytes. An encoder that counted bytes writes 13, and a decoder reading thirteen characters takes one too many, then reads the next element from the wrong place, and everything after that is rubble. This decoder tries both readings and uses the one that holds together, saying so when that is not the one EMVCo specifies.

If you generate these, count characters. An encoder and a decoder that both count bytes agree with each other, so a round-trip test passes, and most test payloads are plain ASCII anyway. That is exactly the kind of luck that lets the bug reach production before anyone notices.

Check the CRC first

Tag 63 is a mandatory CRC-16/CCITT-FALSE over the entire payload up to and including the "6304" header itself, and that inclusion is the detail most implementations get wrong. If the CRC does not match, stop: the payload has been truncated or altered, and every field after the break point is suspect.

The algorithm is polynomial 0x1021, initial value 0xFFFF, no input or output reflection, no final XOR. A quick way to check an implementation: the string 123456789 must produce 29B1.

Static versus dynamic

Tag 01 says which. 11 is static: a printed code taped to a counter, reusable, and usually without an amount, so the consumer types one in. 12 is dynamic, generated for one transaction and intended for single use.

Whether tag 54 carries an amount is a separate question, and EMVCo ties it to whether the app should prompt for one rather than to static or dynamic. Pix shows both directions: a static Pix code may fix an amount, and a dynamic Pix code should leave tag 54 out, because its amount comes from the payload the code's URL points at. So this decoder does not treat either combination as an error.

Where you meet this

PIX in Brazil, PromptPay in Thailand, and most merchant QR schemes across Asia and Latin America are EMVCo MPM underneath, distinguished by the GUID in the merchant account template, for example BR.GOV.BCB.PIX. The shared spec is why one decoder handles all of them.

Note that this is the merchant-presented format. Consumer-presented QR (CPM) is a different, base64-encoded structure that wraps genuine BER-TLV. Paste that into the TLV parser after decoding the base64 with the data converter.

More EMV chip tools

All EMV chip tools