Pix payload (BR Code)

The Pix BR Code payload behind a Pix QR Code and "Pix copia e cola".

  • Parity matrix

Validate

Validates a Pix BR Code payload against the Manual de Padrões para Iniciação do Pix v2.10.0 and, where the manual is silent, the EMV QRCPS-MPM it builds on. The function checks the form of the key, not whether the key is registered in the DICT.

  • Structure: well-formed TLV with every length from 01 to 99, the payload format indicator 000201 as the first object, and the CRC-16 (63) as the last top-level object, whole, matching the payload. Eight trailing characters that only look like 6304 and a checksum (inside another object, for example) do not count as the CRC. A CRC in lowercase hexadecimal is accepted, as in 2.4.0 (no official source fixes the case).
  • An object ID may not repeat at the same level (EMV gives each object one ID per level), whatever the values are, even with a CRC that matches. Until 2.4.0 the last repeated ID won. Only crafted payloads repeat an ID.
  • Mandatory objects: merchant category code (52) of 4 digits, currency (53) 986, country (58) BR in uppercase, merchant name (59) of at most 25 characters and merchant city (60) of at most 15. Only the length is checked: neither Pix manual restricts the characters of the name and the city (EMV types them as ans), so a name with accents is accepted, though pixPayload.generate folds both to printable ASCII.
  • The first Merchant Account Information template (IDs 26 to 51) that carries the br.gov.bcb.pix GUI (case-insensitive) is the one checked, and a template without the GUI is skipped. It holds exactly one of: a Pix key written in its DICT form, as pixKey.getInfo returns it (no mask, lowercase email or UUID, +55 phone), optionally with the 8-digit ISPB of a Pix Saque facilitator (fss, 26-03); or a PSP location (26-25), host and path of at most 77 characters, never next to a fss. The host has dot-separated labels of letters, digits and hyphens with at least one dot, and the path takes only URL path characters (no scheme, port, query string or whitespace).
  • Object 01 is optional. When present, it must be 11 or 12.
  • The amount (54) is digits with an optional . decimal mark (98.73, 98 and 98. are accepted), at most 2 decimals and 13 characters. Zero is accepted only in a Pix Saque (with a fss) or next to a PSP location; a payload with a key alone needs an amount greater than zero.
  • The Additional Data Field Template (62) with the txid (62-05) is mandatory ("sempre presente em um BR Code", §2.6). The txid is *** (no txid) or 1 to 25 letters and digits (§2.6.2). So in a static payload the - of the Manual do BR Code example RP12345678-2019 is excluded.
  • Next to a PSP location, only the presence of 62-05 is checked. §2.7 says a filled txid or amount in a dynamic BR Code must be ignored, so a dynamic payload with a filled 62-05 stays valid.
  • Unreserved templates (IDs 80 to 99) are ignored. A composite Pix Automático QR Code that also carries a key or a payment location is read as an ordinary payload; one that carries only the recurrence, with no key or payment location, is invalid.
  • 2.4.0 checked mostly the structure. It accepted a payload without 62, a txid with -, _ or spaces or over 25 characters, a masked or uppercase key, a phone key without +55, a name or city over the limits, a lowercase country code, a merchant category code that is not 4 digits and an object of length 00. It rejected an amount with a . and no decimals (98.).
  • A value that is not a string is invalid. Whitespace around the payload is ignored.
ParameterTypeRequired
valuestringyes
returnsboolean

Check if a Pix BR Code payload (the string behind a Pix QR Code and behind "Pix copia e cola") is valid under the Manual de Padrões para Iniciação do Pix and, where it is silent, the EMV QR Code specification it builds on.

  • The payload must start with the format indicator 000201.
  • The TLV structure, the CRC-16 and the mandatory objects (format indicator, a 4 digit category code, currency, country, merchant name and city) are checked. An object ID may not repeat at the same level, and the CRC (63) must be the last object of the payload, not eight characters inside another one.
  • One "Merchant Account Information" template (IDs 26 to 51) must carry the br.gov.bcb.pix GUI with a key (static) or a PSP URL (dynamic), never both.
  • The key is written in the DICT form (§2.5.1): the one getPixKeyInfo returns unchanged, so 12345678909 passes and 123.456.789-09 does not. Whether it is registered cannot be told from the payload. The PSP URL has at most 77 characters (§2.5.2).
  • The merchant name has at most 25 characters and the city at most 15; the country is BR in uppercase. Their characters are not restricted (neither manual does, and EMV types them as ans), so a name with accents is accepted, though generatePixPayload folds both to printable ASCII.
  • No BCB manual states the case of the CRC or of BR: the only case rule they give is for the GUI, and every official example writes both in uppercase. Accepting a lowercase CRC (1d3d) and rejecting br are choices of this library, as in 2.4.0.
  • Object 01 (Point of Initiation Method) is optional and must be 11 or 12 when present.
  • Object 62 (Additional Data Field) is mandatory and carries the txid (62-05), "sempre presente em um BR Code": *** or 1 to 25 letters and digits (§2.6.2); with a PSP URL any value stands, since §2.7 has the payer ignore it. The - of the Manual do BR Code example RP12345678-2019 is outside the Pix character set of §2.6.2, so that static example is rejected.
  • An amount (54) is digits with an optional . and at most two decimals (98.73, 98 and 98. are the EMV examples), at most 13 characters, and greater than zero, except in a Pix Saque BR Code (8 digit fss in sub-object 26-03) and next to a PSP location, where the Pix API gives it 0.00 (the Manual do BR Code lists "0" among its examples).
  • Unreserved Templates (IDs 80 to 99) are ignored.
import { isValidPixPayload } from '@brazilian-utils/brazilian-utils';

isValidPixPayload(
  '00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-426655440000' +
    '5204000053039865802BR5913Fulano de Tal6008BRASILIA62070503***63041D3D'
); // true

isValidPixPayload('00020126580014br.gov.bcb.pix...'); // false (broken CRC)

Source: Manual do BR Code, Manual de Padrões para Iniciação do Pix.

Code: brazilian-utils/javascript
Try it with JavaScript isValidPixPayload
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (69) and the result in each library pixPayload.isValid

Generate

Generates a Pix BR Code payload. Give exactly one of a key (static) or a PSP URL (dynamic), otherwise the function returns null.

  • params (GeneratePixPayloadParams): key or url (exactly one), merchantName and merchantCity (required), and the optional amount, txid and description. A value that is not an object returns null.
  • With key the payload is static (object 01 is left out, so it can be paid more than once) and the key is normalized as pixKey.getInfo does. A key that pixKey.getInfo rejects returns null, so an email key with & returns null.
  • With url the payload is dynamic (Point of Initiation 12) and cannot carry an amount or a txid: either returns null. url is the PSP location (field 26-25): a host optionally followed by a path, no scheme (pix.example.com/qr/v2/1234), at most 77 characters. The host has dot-separated labels of letters, digits and hyphens (a hyphen never starts or ends a label) with at least one dot, and the path takes only URL path characters (a % only as the start of a percent-encoded octet, %41). A scheme (https://...), a port, a query string, whitespace, a host without a dot, or an empty or non-string url returns null.
  • merchantName and merchantCity are required: null when either is missing, blank or empty after folding. They are folded to printable ASCII (accents dropped), truncated to 25 and 15 characters, and trimmed after the truncation.
  • amount is written with two decimal places. A value that does not survive that (0.005, 123.456), or that is zero, negative, not finite or longer than 13 characters once written (9999999999.99 is the largest) returns null. Floating-point noise beyond the second decimal, as in 0.1 + 0.2 (written 0.30), is accepted.
  • txid is 1 to 25 letters and digits (default ***, always written in field 62-05). Anything else, *** included, returns null.
  • description loses its accents as the name and city do. It is written in field 26-02, in whatever room is left of the 99 characters of the template after the GUI and the key or URL, and never over 72 characters, trimmed after the truncation, and dropped when nothing is left.
  • Every payload the function returns is one pixPayload.isValid accepts: the key in its DICT form, the 62-05 txid always written, the name and city within their limits and an amount greater than zero, and pixPayload.getInfo reads it back.
  • Pix Saque (fss), unreserved templates (IDs 80 to 99) and composite Pix Automático QR Codes are never written.
ParameterTypeRequired
paramsGeneratePixPayloadParamsyes
params.keystringno
params.urlstringno
params.merchantNamestringyes
params.merchantCitystringyes
params.amountnumberno
params.txidstringno
params.descriptionstringno
returnsstring | null

Generate the payload of a Pix BR Code. Exactly one of params.key or params.url must be given; null is returned when both or neither are given.

  • Params (GeneratePixPayloadParams): key or url, merchantName, merchantCity, and the optional amount, txid and description.
  • With key the payload is static and the key is normalized by getPixKeyInfo. With url it is dynamic (object 01 set to 12) and cannot carry amount or txid.
  • url is a PSP location: host and path, no scheme (pix.example.com/qr/v2/1234), at most 77 characters.
  • amount takes two decimal places; 0.005, 123.456 or a value that rounds to 0.00 is rejected.
  • txid is 1 to 25 characters of [A-Za-z0-9] (default ***).
  • merchantName, merchantCity and description lose their accents and are truncated to 25, 15 and what is left of the template.
import { generatePixPayload } from '@brazilian-utils/brazilian-utils';

generatePixPayload({
  key: '123.456.789-09',
  merchantName: 'Fulano de Tal',
  merchantCity: 'Brasília',
  amount: 123.45
});
// "00020126330014br.gov.bcb.pix0111123456789095204000053039865406123.455802BR5913Fulano de Tal6008Brasilia62070503***630479EE"

generatePixPayload({
  url: 'pix.example.com/qr/v2/1234',
  merchantName: 'Fulano de Tal',
  merchantCity: 'Brasília'
});
// "00020101021226480014br.gov.bcb.pix2526pix.example.com/qr/v2/12345204000053039865802BR5913Fulano de Tal6008Brasilia62070503***6304FC66"

generatePixPayload({ merchantName: 'Fulano', merchantCity: 'Brasília' }); // null (neither key nor url)

Source: Manual do BR Code, Manual de Padrões para Iniciação do Pix.

Code: brazilian-utils/javascript
Try it with JavaScript generatePixPayload
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (36) and the result in each library pixPayload.generate

Decode

Parses a Pix BR Code payload into its fields. Returns null exactly when pixPayload.isValid returns false, never a partial result.

  • Fields: merchant name and city, point of initiation (dynamic when there is a PSP location or object 01 is 12, static otherwise, so a key payload with 01 = 12 is dynamic) and either the key (static) or the URL (dynamic).
  • Amount (a number, so 98. reads as 98), txid, description (26-02) and the withdrawal facilitator of a Pix Saque (fss, the 8-digit ISPB in 26-03) are present only when the payload carries them. The *** txid marker means no txid.
  • With a PSP location, the function leaves out the amount and the txid, as §2.7 of the manual requires ("Se preenchidos, seu conteúdo deve ser ignorado").
  • Every rule of pixPayload.isValid applies, so a payload without object 62, with a static txid outside 1 to 25 letters and digits, or with a key not in its DICT form returns null. 2.4.0 parsed those payloads.
  • A repeated object ID, a CRC that is not the last top-level object and every other rule of pixPayload.isValid return null, so the payload is never partly read. A value that is not a string returns null.
  • A composite Pix Automático QR Code that also carries a key or a payment location is read as an ordinary payload, its recurrence location dropped. Whitespace around the payload is ignored.
ParameterTypeRequired
valuestringyes
returnsPixPayloadInfo | null

Parse a Pix BR Code payload into its fields. Accepts what isValidPixPayload accepts and returns null for anything else, never a partial result.

  • Returns a PixPayloadInfo: merchantName, merchantCity, pointOfInitiation and either key (static) or url (dynamic).
  • amount, txid, description and withdrawalFacilitator (the fss of a Pix Saque) are present only when the payload carries them. txid is absent for the *** marker.
  • pointOfInitiation (PixPointOfInitiation) is "dynamic" when the payload carries a PSP location (a dynamic QR Code in the Pix manual, §2.4.2) or marks itself single use with object 01 = "12" (§2.7.2), "static" otherwise. A key payload with 01 = "12" is therefore "dynamic"; url and key tell the two kinds of QR Code of the manual apart.
  • With a PSP location, amount and txid are ignored and left out, as §2.7 of the manual mandates ("Se preenchidos, seu conteúdo deve ser ignorado").
import { getPixPayloadInfo } from '@brazilian-utils/brazilian-utils';

getPixPayloadInfo(
  '00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-426655440000' +
    '5204000053039865802BR5913Fulano de Tal6008BRASILIA62070503***63041D3D'
);
// {
//   merchantName: 'Fulano de Tal',
//   merchantCity: 'BRASILIA',
//   pointOfInitiation: 'static',
//   key: '123e4567-e12b-12d1-a456-426655440000'
// }

Source: Manual do BR Code, Manual de Padrões para Iniciação do Pix.

Code: brazilian-utils/javascript
Try it with JavaScript getPixPayloadInfo
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (33) and the result in each library pixPayload.getInfo

Official sources

See also Pix key

Last updated on

On this page