07 — PIX / Bolepix¶
O Bolepix é o boleto híbrido: um boleto tradicional com QR Code PIX impresso, pagável pelo código ou pela linha digitável. A PyCobrança gera o payload PIX (BR Code), o QR Code e o segmento PIX no CNAB de remessa.
Dois QR diferentes — e a diferença custa dinheiro¶
Só o QR que o banco gerou liquida o boleto
| Como nasce | O que acontece ao pagar | |
|---|---|---|
Bolepix (pix_copia_cola) |
o banco gera no registro da cobrança; QR dinâmico, com o mesmo identificador do título | credita e dá baixa no boleto; duplicidade bloqueada |
PIX avulso (pix_chave) |
montado aqui, a partir da chave; BR Code estático | credita a chave, mas o título fica em aberto |
Pagar um QR avulso não quita o boleto: o banco não sabe que aquele PIX se refere a este título. Sem conciliação manual, o pagador pode ser cobrado de novo pelo código de barras, ou o título ir a protesto já pago.
O contexto e o BoletoEmitido dizem qual é qual — vinculado / pix_vinculado. Se você
expõe o QR a pagadores, use esse campo para decidir o que rotular.
A cobrança híbrida da Resolução BCB 587 é a primeira linha, não a segunda
A Resolução BCB nº 587
(18/09/2026) dá nome próprio a cobrança híbrida — boleto e QR Pix no mesmo documento —, com
vigência em 1º/02/2027. Ela corresponde ao pix_copia_cola, e o texto exclui o outro
caminho por dois motivos independentes: a modalidade é restrita a Pix Cobrança com
vencimento (art. 11-AA, §2º), que é dinâmico, e exige que o PSP do recebedor seja a mesma
instituição que emitiu o boleto (§5º) — o que a chave informada em pix_chave não garante.
"Híbrido", no topo desta página, descreve o documento; na resolução, nomeia a modalidade. O QR avulso continua servindo para receber, com a ressalva do quadro acima — só não é aquilo.
Nada a fazer por prazo: a modalidade é facultativa para as instituições e vale só para títulos com vencimento. Quem gera o QR é o banco, como já é hoje.
Identificando o QR avulso — e conciliando depois¶
Como o QR avulso não dá baixa, o identificador deixa de ser conveniência e vira o que torna a conciliação possível. São dois campos, com papéis distintos:
| Campo | No payload | Limite | Para quê |
|---|---|---|---|
pix_txid |
62-05 | 25, A-Za-z0-9 |
identificar a transação — costuma aparecer no memo do crédito no extrato |
pix_observacao |
26-02 | 40, sem acentos | descrever a cobrança para quem paga |
O QR avulso já sai identificado. Sem pix_txid, o campo 62-05 é preenchido com o nosso
número (só A-Za-z0-9, cortado em 25) — txid_do_titulo(). Deixar isso na lembrança de quem
chama garantiria que uma parte dos boletos saísse sem identificador, e é justamente aí que o
recebimento fica órfão. Para abrir mão de propósito, informe pix_txid="***", que é o ausente
do padrão EMV.
O valor também vai, no campo 54 — o pagador não digita, e portanto não digita errado.
Ainda não tem o nosso número?
Sem nosso número, o txid sai ausente (***) em vez de derivado: nosso_numero_formatado()
completaria com zeros e ainda calcularia o dígito em cima deles, produzindo um identificador
plausível e sem significado — que não casa com título nenhum na conciliação.
E o QR não depende do boleto. Ele precisa de chave, nome, cidade e valor; o nosso número é
exigência do código de barras, não do PIX. Para emitir o QR antes de ter o número, use o
PixPayload direto:
from pycobranca.pix import PixPayload, qr_matrix
payload = PixPayload(
chave="11222333000181",
nome="Empresa Exemplo LTDA",
cidade="SAO PAULO",
valor="127.50",
info_adicional="Fatura 2026-0001",
)
copia_cola = payload.br_code()
matriz = qr_matrix(copia_cola)
Quando o nosso número chegar, monte o boleto normalmente — aí o txid passa a ser derivado e
a conciliação fica possível.
Isso fecha o ciclo com a conciliação OFX, que casa pelo memo:
titulo = Bancos.find("341")(..., pix_chave="...", pix_txid="NN10912345678")
# o pagador lê o QR e paga; o credito entra no extrato com o txid no memo
resultado = concilia(extrato, ["NN10912345678"])
resultado.conciliadas # o crédito PIX casado com o título
resultado.pendentes # os que ainda não apareceram
Sem identificador, o recebimento fica órfão no extrato e o boleto parece não pago — que é exatamente o risco do QR avulso.
O pix_txid é validado na composição: fora de A-Za-z0-9 ou acima de 25 caracteres, levanta
PixInvalido aqui, e não vira recusa no banco.
O caminho vinculado¶
A biblioteca não registra a cobrança: isso é chamada online ao PSP, fora do escopo (00 — Visão geral). Quem registra é você — pela API do banco ou pelo arquivo retorno, onde o payload volta. Aí basta passá-lo:
boleto = Bancos.find("341")(..., pix_copia_cola=payload_que_o_banco_devolveu)
ctx = boleto.contexto_render() # ctx["pix"]["vinculado"] is True
O payload vai para o QR exatamente como veio — reescrevê-lo imprimiria um código que o banco
não reconhece. pix_copia_cola tem precedência sobre pix_chave, e funciona em qualquer
banco: suporta_pix restringe a geração local, não o que o banco produziu.
Componentes¶
pix/
├── payload.py # BR Code / EMV (copia-e-cola) + CRC16
└── qr.py # matriz de módulos (qr_matrix) e SVG (qr_svg)
BR Code (EMV)¶
O payload PIX segue o padrão EMV® QR Code do Banco Central. É uma string estruturada em campos ID-Length-Value (TLV). Campos essenciais:
| ID | Campo | Observação |
|---|---|---|
| 00 | Payload Format Indicator | Fixo 01. |
| 26 | Merchant Account Information | Contém GUI br.gov.bcb.pix + chave + info adicional. |
| 52 | Merchant Category Code | MCC. |
| 53 | Transaction Currency | 986 (BRL). |
| 54 | Transaction Amount | Valor. |
| 58 | Country Code | BR. |
| 59 | Merchant Name | Beneficiário. |
| 60 | Merchant City | Cidade. |
| 62 | Additional Data | txid. |
| 63 | CRC16 | Checksum (CRC-CCITT). |
O payload.py monta a string, calcula o CRC16-CCITT e retorna o copia-e-cola.
QR Code¶
qr.py gera a matriz de módulos do QR a partir do payload; o pacote render/ a desenha
vetorialmente no PDF. A geração é pura Python (sem dependências de sistema).
Status: implementado (
pycobranca/pix/): payload EMV validado byte a byte contra o exemplo canônico do manual do BCB (CRC1D3D), QR real viaqrcode(dependência do pacote) e round-trip verificado — o QR desenhado no PDF decodifica de volta ao copia-e-cola.
API real¶
from pycobranca.pix import PixPayload, qr_matrix, qr_svg
pix = PixPayload(
chave="11222333000181", # CNPJ do beneficiário
nome="Empresa Exemplo LTDA",
cidade="Sao Paulo",
valor="127.50",
txid="PYCOB0001",
)
copia_cola = pix.br_code() # string EMV com CRC16
matriz = qr_matrix(copia_cola) # matriz 0/1 (consumida pelo ReportLab)
svg = qr_svg(copia_cola) # SVG para pré-visualização
No boleto, o QR Code (Bolepix) é posicionado na Ficha de Compensação, no modelo moderno — veja o exemplo visual em boleto-pix.png (saída real do ReportLab).
Ao emitir um boleto de banco com PIX habilitado, o Bolepix é montado automaticamente:
boleto = Bancos.find("341")(..., pix_chave="11222333000181", pix_txid="PYCOB0001")
ctx = boleto.contexto_render() # pix = {habilitado, copia_cola, qrcode_matrix}
pdf = render_boleto_pdf(ctx, modelo="moderno") # QR real na ficha
Segmento PIX no CNAB¶
Na remessa, os bancos com PIX exigem informações adicionais (ex.: segmento específico ou campos
no segmento R do CNAB 240). O subsistema CNAB inclui esses campos quando o boleto carrega dados
de PIX e o banco está em Bancos.com_pix().
Bancos com PIX¶
suporta_pix = True significa uma coisa precisa: o segmento PIX do CNAB daquele banco está
implementado — registro tipo 8 no 400, segmento Y-03 no 240. São eles que levam a chave DICT e o
txid ao banco, para que ele registre a cobrança e gere o QR vinculado. Consultável em
Bancos.com_pix(); hoje: Banco do Brasil, Santander, Caixa, Bradesco, C6, Itaú e Sicoob.
Nos demais bancos a ausência é de segmento no layout, não de capacidade PIX da instituição.
Fechar essa lacuna exige, por banco, o manual definindo o segmento — o mesmo critério de
15 — Novo banco. E, em qualquer banco, pix_copia_cola já funciona: se você
tem o payload do banco, a biblioteca o imprime.
Legibilidade do QR impresso¶
Payload correto não garante QR legível: entre a matriz de módulos e o papel está a rasterização,
onde os módulos caem em fração de pixel. tests/test_pix_leitura.py fecha esse ciclo —
decodifica o QR do PDF renderizado e compara com o payload, nos dois modelos e em todos os
bancos com PIX.
O que a medição mostra: de 200 dpi para cima todos leem; a 150 dpi dois dos sete payloads já não são lidos. Boleto se imprime a 300 dpi, então a margem é confortável — mas se você gera pré-visualização em resolução baixa, não a use para conferir leitura.
A matriz sai com border=0: a zona de silêncio da norma (4 módulos) vem do fundo branco do
boleto, já que o QR é posicionado com folga. Reutilizando qr_matrix em outro suporte, reserve
essa margem — sem ela o leitor não isola o símbolo do que estiver ao redor.
Validação¶
- CRC16 conferido em todos os payloads gerados.
- Testes de payload contra exemplos conhecidos (copia-e-cola de referência).
- Validação de tamanho e presença de campos obrigatórios do EMV.