Emitir boleto
Emitir um boleto usa o scope charges:create. O Vmix Pay registra o boleto no
banco e devolve a linha digitável, o código de barras, o nosso número e
(no boleto híbrido) o QR Code copia-e-cola.
Os 2 tipos de boleto
Seção intitulada “Os 2 tipos de boleto”tipo |
O que é |
|---|---|
boleto |
Boleto bancário tradicional (sem PIX). O campo qr_code da resposta vem null. |
boleto_hibrido |
Boleto com PIX embutido — o pagador quita o mesmo documento por boleto ou lendo o QR Code (qr_code na resposta). É a forma de oferecer “PIX + boleto” numa cobrança só. |
Criar um boleto
Seção intitulada “Criar um boleto”POST /v1/charges/boleto — exige charges:create e o header Idempotency-Key
(obrigatório). O corpo:
tipo— um dos dois tipos acima.valorCents— apesar do nome, é uma string decimal em reais ("199.90"), como oamountdo PIX. Nunca um número.dataVencimento— string no formatoYYYY-MM-DD(data válida e futura).pagador— dados do cliente final (PII), um objeto com os campos abaixo. O endereço é obrigatório para o registro no banco.descricao— texto livre, opcional.external_id— opcional. O seu identificador para este boleto (o número da fatura/pedido no seu sistema). Vem de volta na resposta e é o que permite, depois, cancelar ou alterar o vencimento do boleto pelo seu próprio código, sem precisar guardar ocharge_iddo Vmix Pay (ver Cancelar/baixar pelo seu identificador e Alterar a data de vencimento).integrador_code— opcional. Só para integradores parceiros. É o código do parceiro (formatoINTG-XXXXXX, fornecido pela equipe Vmix Pay) que originou a cobrança — é assim que se sabe que o boleto foi emitido por aquele parceiro, para a bonificação (revenue-share). Carimbado de forma imutável na criação; código inexistente/inativo →400 INTEGRADOR_CODE_INVALID(o boleto não é criado). Não confunda comexternal_id:integrador_codediz quem originou;external_idé o seu número para aquela cobrança. Detalhes em Atribuição de cobrança ao integrador.account_id— opcional; se presente, deve bater com a conta do seu token (senão403).
Campos do pagador
Seção intitulada “Campos do pagador”| Campo | Obrigatório | Descrição |
|---|---|---|
nome |
sim | Nome do pagador. |
documento |
sim | CPF ou CNPJ — apenas os dígitos. O tipo é declarado em tipoPessoa. |
tipoPessoa |
sim | Tipo de pessoa: PESSOA_FISICA (documento = CPF) ou PESSOA_JURIDICA (documento = CNPJ). |
cep |
sim | CEP do endereço (só dígitos). |
logradouro |
sim | Rua/avenida. |
numero |
não | Número do endereço (opcional — nem todo endereço tem). |
cidade |
sim | Cidade. |
uf |
sim | Unidade federativa, 2 letras (ex.: PR). |
curl -X POST https://api.vmixpay.com.br/v1/charges/boleto \ -H "Authorization: Bearer SEU_ACCESS_TOKEN" \ -H "Idempotency-Key: 7d8e9f0a-1b2c-4d3e-8f9a-0b1c2d3e4f5a" \ -H "Content-Type: application/json" \ -d '{ "tipo": "boleto_hibrido", "valorCents": "199.90", "dataVencimento": "2026-07-15", "descricao": "Mensalidade junho", "external_id": "fatura-88620", "pagador": { "nome": "Cliente Exemplo", "documento": "00000000000", "tipoPessoa": "PESSOA_FISICA", "cep": "85000000", "cidade": "Guarapuava", "logradouro": "Rua Exemplo", "numero": "123", "uf": "PR" } }'import { randomUUID } from "node:crypto";
const res = await fetch("https://api.vmixpay.com.br/v1/charges/boleto", { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Idempotency-Key": randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ tipo: "boleto_hibrido", valorCents: "199.90", dataVencimento: "2026-07-15", descricao: "Mensalidade junho", pagador: { nome: "Cliente Exemplo", documento: "00000000000", tipoPessoa: "PESSOA_FISICA", cep: "85000000", cidade: "Guarapuava", logradouro: "Rua Exemplo", numero: "123", uf: "PR", }, }),});
const boleto = await res.json();A resposta é 201 para um boleto novo (ou 200 num replay idempotente):
{ "charge_id": "9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c", "external_id": "fatura-88620", "public_id": "pub_AbC123XyZ", "payment_method": "boleto_hibrido", "status": "pending", "amount": "199.90", "boleto": { "nosso_numero": "000000012345678", "seu_numero": "pedido-123", "linha_digitavel": "00190.00009 01234.567890 12345.678901 2 99990000019990", "codigo_barras": "00192999900000199900000001234567891234567890", "qr_code": "00020126...5204000053039865802BR...6304ABCD", "tipo_cobranca": "boleto_hibrido", "data_vencimento": "2026-07-15" }, "created_at": "2026-06-22T12:00:00.000Z"}linha_digitavel— a linha digitável (para digitação no app do banco).codigo_barras— o código de barras numérico.nosso_numero— o identificador do boleto no banco.qr_code— o copia-e-cola PIX no tipoboleto_hibrido;nullnoboletotradicional.public_id— token da página pública de pagamento (/pagar/{public_id}).external_id— o seu identificador, ecoado de volta como você enviou (ounullse você não mandou). Guarde-o para depois cancelar/alterar por referência.
| Erro | Quando |
|---|---|
400 IDEMPOTENCY_KEY_REQUIRED |
Header Idempotency-Key ausente. |
400 AMOUNT_INVALID |
valorCents malformado. |
400 INVALID_DUE_DATE |
dataVencimento impossível (ex.: 2026-13-40). |
403 ACCOUNT_MISMATCH |
account_id informado não bate com a conta do token. |
409 IDEMPOTENCY_KEY_REUSED |
Mesma Idempotency-Key com corpo diferente. |
422 MERCHANT_ADDRESS_REQUIRED |
O endereço do beneficiário (sua empresa) está incompleto no cadastro. |
502 BANK_UNAVAILABLE |
Falha ao registrar no banco; re-tentável. |
Baixar o PDF do boleto
Seção intitulada “Baixar o PDF do boleto”GET /v1/charges/boleto/{id}/pdf — exige charges:read. Responde
application/pdf como anexo (attachment).
curl https://api.vmixpay.com.br/v1/charges/boleto/9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c/pdf \ -H "Authorization: Bearer SEU_ACCESS_TOKEN" \ -o boleto.pdfUm id que não exista, seja de outro merchant, ou não corresponda a um boleto,
retorna 404 genérico (tenant-safe).
Como saber que o boleto foi pago (a baixa)
Seção intitulada “Como saber que o boleto foi pago (a baixa)”Quando o pagador quita o boleto — pela linha digitável ou pelo QR Code PIX do boleto híbrido — o Vmix Pay avisa o seu sistema de duas formas independentes. Use as duas: o push é imediato, o pull é a rede de segurança.
1. Push — o webhook payment.received
Seção intitulada “1. Push — o webhook payment.received”Cadastre a URL que vai receber a baixa em /painel/webhooks (uma URL por conta,
que recebe os eventos de todas as cobranças dela). Assim que o pagamento é confirmado,
enviamos um POST para ela:
POST /seu/endpoint/de/baixa HTTP/1.1Content-Type: application/jsonX-Vmix-Event: payment.receivedX-Vmix-Timestamp: 1785193500X-Vmix-Signature: sha256=3f9a...X-Vmix-Delivery-Id: 8c1e4b2a-...
{ "event": "payment.received", "event_id": "550e8400-e29b-41d4-a716-446655440000", "charge_id": "9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c", "account_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "status": "paid", "amount": "199.90", "external_id": "88620", "paid_at": "2026-06-22T12:00:00.000Z"}Para dar baixa no seu documento, você precisa correlacionar a cobrança. Duas formas, e a primeira é bem mais simples:
external_id— envie o número do seu documento/fatura na criação da cobrança ("external_id": "88620"). Ele volta na consulta e no webhook, então a baixa é uma busca direta pelo seu próprio número.charge_id— o identificador do Vmix Pay. Funciona, mas exige que você guarde esse id no momento da criação para consultar depois.
O transporte é at-least-once: a mesma baixa pode chegar mais de uma vez (retry após
falha de rede, por exemplo). Deduplique pelo event_id e responda 2xx também
para o duplicado — qualquer resposta fora de 2xx faz o Vmix Pay reenviar.
2. Pull — consulta
Seção intitulada “2. Pull — consulta”Se um webhook se perder (endpoint fora do ar, deploy, rota errada), o pagamento não se perde: ele está registrado aqui e você o encontra por consulta.
# a cobrança específica — status vira "paid" e ganha o bloco "payment"curl https://api.vmixpay.com.br/v1/charges/{charge_id} \ -H "Authorization: Bearer SEU_ACCESS_TOKEN"
# ou todos os pagamentos recebidos num período (scope payments:read)curl "https://api.vmixpay.com.br/v1/payments?paid_from=2026-07-01&paid_to=2026-07-31" \ -H "Authorization: Bearer SEU_ACCESS_TOKEN"O event_id do feed GET /v1/events?type=payment.received é o mesmo do webhook —
use-o para deduplicar push e pull entre si. Veja
Consultar pagamentos.
Cancelar um boleto
Seção intitulada “Cancelar um boleto”POST /v1/charges/{charge_id}/cancel — exige o scope charges:create. Responde
200 com a mesma projeção da cobrança, agora com status: "cancelled".
Use o charge_id (o mesmo da criação/consulta) — não o nosso_numero.
curl -X POST \ https://api.vmixpay.com.br/v1/charges/9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c/cancel \ -H "Authorization: Bearer SEU_ACCESS_TOKEN"A resposta é a mesma projeção do GET /v1/charges/{charge_id} (campos abreviados abaixo):
{ "charge_id": "9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c", "external_id": "pedido-123", "public_id": "pub_AbC123XyZ", "status": "cancelled", "amount": "199.90", "pix": null, "payment": null}Só uma cobrança pending pode ser cancelada. Qualquer estado terminal
(paid, cancelled, expired, failed) devolve 409 CHARGE_NOT_PENDING. Um boleto
vencido é marcado expired antes da checagem — então cancelá-lo também dá 409.
A operação é idempotente na prática: cancelar de novo devolve 409, nunca
desfaz nem cobra duas vezes.
Ao cancelar, o Vmix Pay emite o evento charge.cancelled — entregue no seu
webhook e disponível no feed de eventos. O payload traz
reason: "cancelled" (cancelamento explícito, como este).
| Erro | Quando |
|---|---|
409 CHARGE_NOT_PENDING |
A cobrança não está pending (já paga, cancelada, expirada ou falha). |
502 BANK_UNAVAILABLE |
Falha ao baixar o boleto no banco. A cobrança segue pending (não foi cancelada) — re-tentável. |
404 CHARGE_NOT_FOUND |
charge_id inexistente, de outro merchant, ou de outro modo (teste ↔ produção). Genérico por segurança — nunca revela existência. |
403 |
Token sem o scope charges:create. |
Cancelar/baixar pelo seu identificador (ou por pagamento externo)
Seção intitulada “Cancelar/baixar pelo seu identificador (ou por pagamento externo)”Às vezes você não tem o nosso charge_id em mãos — só o número da fatura no
seu sistema (o external_id que você enviou na criação). E às vezes o boleto precisa
ser encerrado porque o cliente pagou por outra forma (dinheiro, PIX avulso, cartão no
seu sistema), não porque foi cancelado. Para os dois casos existe:
POST /v1/charges/cancel — exige o scope charges:create. O corpo aceita um
identificador e um motivo opcional:
| Campo | Obrigatório | Descrição |
|---|---|---|
charge_id |
um dos dois | O nosso UUID (o mesmo da criação/consulta). |
external_id |
um dos dois | O seu identificador enviado na criação (ex.: o número da fatura). |
reason |
não | cancelled (padrão) ou paid_externally. |
Informe exatamente um entre charge_id e external_id — nenhum, ou os dois, dá 400.
# Por external_id, porque o cliente pagou por outra forma no seu sistema:curl -X POST https://api.vmixpay.com.br/v1/charges/cancel \ -H "Authorization: Bearer SEU_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "external_id": "fatura-88620", "reason": "paid_externally" }'A resposta é a mesma projeção do cancelamento por id (status: "cancelled"), e o
comportamento de baixa-no-banco-antes-de-cancelar é idêntico (o mesmo 502
re-tentável se o banco não confirmar a baixa).
Além dos erros da tabela acima, cancelar por external_id tem dois específicos:
| Erro | Quando |
|---|---|
404 CHARGE_NOT_FOUND |
Nenhuma cobrança pendente com esse external_id. |
409 CANCEL_REFERENCE_AMBIGUOUS |
Mais de uma cobrança pendente com o mesmo external_id (ele não é único). Cancele pelo charge_id específico. |
400 CANCEL_REFERENCE_REQUIRED |
Você não informou nenhum identificador, ou informou os dois. |
Alterar a data de vencimento
Seção intitulada “Alterar a data de vencimento”Quando o cliente consegue mais prazo (um acordo no seu sistema), o boleto precisa passar a vencer na nova data — no banco, não só no nosso registro.
PATCH /v1/charges/due-date — exige o scope charges:create. O corpo aceita um
identificador (charge_id ou external_id) e a nova due_date (YYYY-MM-DD):
curl -X PATCH https://api.vmixpay.com.br/v1/charges/due-date \ -H "Authorization: Bearer SEU_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "external_id": "fatura-88620", "due_date": "2026-09-30" }'A resposta é a mesma projeção da cobrança, já com a nova due_date. Só uma cobrança
pending pode ter o vencimento alterado.
| Erro | Quando |
|---|---|
400 INVALID_DUE_DATE |
due_date ausente, malformada, data inexistente ou no passado. |
404 CHARGE_NOT_FOUND |
Nenhuma cobrança pendente com esse identificador, ou de outro merchant/modo. |
409 CHARGE_NOT_PENDING |
A cobrança não está mais pending. |
409 CANCEL_REFERENCE_AMBIGUOUS |
Mais de uma cobrança pendente com o mesmo external_id — use o charge_id. |
502 BANK_UNAVAILABLE |
O banco não confirmou a alteração. Nada mudou — re-tentável. |