PixBrcode

CI Hex.pm Docs License

Generate, parse and validate Pix "copia e cola" payloads (BR Code), the text behind every Pix QR code.

Installation

def deps do
  [
    {:pix_brcode, "~> 0.2.0"}
  ]
end

Usage

Static payload

PixBrcode.encode(%{
  key: "pix@bcb.gov.br",
  merchant_name: "Fulano de Tal",
  merchant_city: "Brasília",
  amount: 1050,        # integer cents, or the string "10.50"
  txid: "ORDER42",     # optional, defaults to "***"
  description: "Thanks" # optional
})
#=> {:ok, "00020126...6304XXXX"}

Dynamic payload

PixBrcode.encode_dynamic(%{
  url: "pix.example.com/qr/v2/9d36b84f",  # without https://
  merchant_name: "Fulano de Tal",
  merchant_city: "Brasilia"
})

Parsing and validating

PixBrcode.decode("00020126580014br.gov.bcb.pix0136123e4567-e12b-12d1-a456-4266554400005204000053039865802BR5913Fulano de Tal6008BRASILIA62070503***63041D3D")
#=> {:ok,
#=>  %PixBrcode.Payload{
#=>    type: :static,
#=>    key: "123e4567-e12b-12d1-a456-426655440000",
#=>    merchant_name: "Fulano de Tal",
#=>    merchant_city: "BRASILIA",
#=>    txid: "***",
#=>    amount: nil, description: nil, url: nil
#=>  }}

PixBrcode.valid?("not a pix")
#=> false

decode/1 checks the CRC, the structure, the br.gov.bcb.pix GUI and the key format, and returns the key in canonical form. Check digits are not verified when decoding, since the CRC already guarantees the payload is intact. Leading/trailing whitespace is ignored.

Errors

All functions return {:ok, result} or {:error, reason}:

Reason When
:missing_required_fields a required field is missing or is not a string
:invalid_key key does not match any DICT format, or CPF/CNPJ has wrong check digits
:invalid_key_type :key_type is not one of :cpf, :cnpj, :phone, :email, :evp
:invalid_merchant_name / :invalid_merchant_city empty, too long, or not printable ASCII after removing accents
:invalid_description not a string, or not printable ASCII after removing accents
:invalid_amount not positive integer cents nor a "10.50" string, or over 13 characters
:invalid_txid not "***" nor 1–25 letters/digits
:invalid_url empty or contains a protocol (https://)
{:too_long, id} field id would exceed 99 characters
:invalid_crc / :invalid_tlv / :invalid_format / :invalid_gui / :missing_key when decoding

QR code image

Generating the image is out of scope, so any QR code library works. With eqrcode:

{:ok, payload} = PixBrcode.encode(%{key: "pix@bcb.gov.br", merchant_name: "Fulano", merchant_city: "Brasilia"})

svg = payload |> EQRCode.encode() |> EQRCode.svg()

Specification

Based on the Central Bank of Brazil's Manual do BR Code (EMV QRCPS-MPM) and the key formats of the DICT API and the Manual Operacional do DICT (v8.5, alphanumeric CNPJ).

License

MIT — Igor Giamoniano.