Pular para o conteúdo

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.

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ó.

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 o amount do PIX. Nunca um número.
  • dataVencimento — string no formato YYYY-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 o charge_id do 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 (formato INTG-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 com external_id: integrador_code diz 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ão 403).
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).
Terminal window
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"
}
}'

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 tipo boleto_hibrido; null no boleto tradicional.
  • public_id — token da página pública de pagamento (/pagar/{public_id}).
  • external_id — o seu identificador, ecoado de volta como você enviou (ou null se 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.

GET /v1/charges/boleto/{id}/pdf — exige charges:read. Responde application/pdf como anexo (attachment).

Terminal window
curl https://api.vmixpay.com.br/v1/charges/boleto/9b2f1c7a-3d4e-4f5a-8b6c-7d8e9f0a1b2c/pdf \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-o boleto.pdf

Um id que não exista, seja de outro merchant, ou não corresponda a um boleto, retorna 404 genérico (tenant-safe).

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.

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.1
Content-Type: application/json
X-Vmix-Event: payment.received
X-Vmix-Timestamp: 1785193500
X-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.

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.

Terminal window
# 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.

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.

Terminal window
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.

Terminal window
# 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.

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):

Terminal window
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.