Criar cobrança por boleto
Boleto é liberado por conta. Se a sua ainda não estiver habilitada, a chamada retorna 400 com "Boleto não está habilitado para esta conta." — fale com o suporte para ativar. O contrato PIX (POST /v1/pix) não muda.
Request
Cabeçalhos
| Cabeçalho | Obrigatório | Descrição |
|---|---|---|
Authorization | sim | Bearer <SUA_API_KEY> |
Content-Type | sim | application/json |
Corpo
{
"amountCents": 5000,
"externalRef": "pedido-123",
"description": "Pedido 123",
"dueDate": "2026-09-30",
"customer": {
"name": "Maria Silva",
"email": "maria@exemplo.com",
"phone": "11999998888",
"document": {
"number": "12345678901",
"type": "cpf"
},
"address": {
"street": "Rua das Flores",
"number": "100",
"complement": "Apto 12",
"district": "Centro",
"city": "São Paulo",
"zipCode": "01310100",
"state": "SP"
}
}
}| Campo | Tipo | Obrig. | Descrição |
|---|---|---|---|
amountCents | inteiro | sim | Valor em centavos. Mínimo: 100 (R$ 1,00). Limites por conta se aplicam. |
customer | objeto | sim | Dados do pagador (ver abaixo). |
customer.name | string | sim | Nome do pagador. Máx. 100 caracteres. |
customer.email | string | sim | E-mail válido do pagador. |
customer.phone | string | condicional | Telefone com DDD, somente números: 11 dígitos = celular, 10 = fixo. Obrigatório em contas que exigem os dados completos do pagador (ver abaixo). Nas demais é opcional e, se o provedor recusar o telefone informado, o boleto é emitido sem ele (não bloqueia a cobrança). |
customer.document.number | string | sim | CPF (11 dígitos) ou CNPJ (14 dígitos). Formatação é removida. |
customer.document.type | string | sim | "cpf" ou "cnpj" (case e espaços normalizados). |
customer.address | objeto | condicional | Endereço do pagador. Obrigatório em contas que exigem os dados completos do pagador; nas demais é ignorado. |
customer.address.street | string | condicional | Logradouro. Máx. 120 caracteres. |
customer.address.number | string | não | Número. Máx. 20 caracteres. |
customer.address.complement | string | não | Complemento. Máx. 60 caracteres. |
customer.address.district | string | condicional | Bairro. Máx. 60 caracteres. |
customer.address.city | string | condicional | Cidade. Máx. 60 caracteres. |
customer.address.zipCode | string | condicional | CEP com 8 dígitos. Formatação é removida. |
customer.address.state | string | condicional | UF com 2 letras, ex.: "SP". |
externalRef | string | não | Identificador no seu sistema. Usado como chave de idempotência. |
description | string | não | Texto livre. Máx. 200 caracteres. |
dueDate | string | não | Vencimento em YYYY-MM-DD, hoje ou futuro. Default: hoje + 3 dias. |
Algumas contas exigem e-mail, telefone e endereço do pagador para emitir boleto. Nelas, faltar ou errar um desses campos retorna 400 apontando qual (ex.: "customer.address.zipCode inválido (CEP com 8 dígitos)."), sem criar a cobrança, e o vencimento precisa ser hoje ou uma data futura. Recomendamos enviar sempre os dados completos: nas contas que não exigem, o endereço é ignorado.
Reenviar a mesma externalRef retorna o boleto original com "idempotent": true, sem emitir outro. Use sempre que possível, especialmente em retries de timeout. Se a emissão anterior ficou em verificação, o reenvio responde 400 com "Boleto em verificação..." até a confirmação: consulte a transação indicada na mensagem e não emita outro boleto para o mesmo pedido enquanto isso. Confirmada a emissão, o mesmo reenvio devolve o boleto (200, "idempotent": true).
Resposta 201 Created
{
"success": true,
"transactionId": "5glmNaIVteNioH6UBNxH",
"status": "pending",
"method": "boleto",
"amountCents": 5000,
"amount": 50,
"dueDate": "2026-09-30",
"bankSlipUrl": "https://southamerica-east1-coufai.cloudfunctions.net/payments-boletoPdf?tid=5glmNaIVteNioH6UBNxH&t=...",
"identificationField": "46191110000000000000013187639011415640000005000",
"nossoNumero": "13187639",
"externalRef": "pedido-123",
"idempotent": false
}| Campo | Descrição |
|---|---|
transactionId | ID interno da transação. Use em GET /v1/transactions/{id}. |
status | Sempre "pending" na criação. |
bankSlipUrl | Link público do PDF do boleto, servido pela Coufai. Pode ser enviado ao pagador; não exige autenticação. Pode vir null logo após a emissão, enquanto o banco conclui o registro (normalmente menos de um minuto); consulte a transação em seguida. Em algumas contas o boleto é entregue só pela linha digitável, sem PDF: aí o bankSlipUrl fica null de forma definitiva e você deve mostrar a identificationField ao pagador. |
identificationField | Linha digitável (47 dígitos) para pagamento no internet banking. Pode vir null pelo mesmo motivo do bankSlipUrl. |
nossoNumero | Número do boleto no banco emissor. Pode vir null, conforme o banco emissor. |
dueDate | Vencimento aplicado. |
amountCents / amount | Eco do valor, em centavos e em reais. |
Resposta 200 OK (idempotente)
Quando externalRef já foi usada antes, a resposta é a cobrança original com "idempotent": true.
Ciclo de vida e webhooks
| Momento | Status da transação | Evento de webhook |
|---|---|---|
| Emissão | pending | — |
| Pagamento compensado pelo banco (normalmente D+1 útil) | paid | transaction.paid, com netCents já descontada a taxa |
| Vencido sem pagamento | expired | transaction.expired — traz unpaidFeeCents se a sua conta tem taxa de boleto não pago |
O boleto pode ser pago após o vencimento enquanto o banco aceitar; nesse caso o transaction.paid chega normalmente. O valor creditado no saldo é netCents (valor menos a taxa de boleto da sua conta). O method da transação é "boleto" em todos os eventos.
Reaja ao transaction.paid e mantenha seu saldo a partir de netCents. A Coufai reconcilia pagamentos com o banco em segundo plano; um pagamento cujo aviso demorou é creditado mesmo assim.
Taxa de boleto não pago
Contas com taxa de boleto não pago configurada são cobradas quando o boleto vence sem pagamento: no momento do expired, o valor da taxa é debitado do saldo e o evento transaction.expired traz unpaidFeeCents (omitido quando não há taxa). Regras:
- Aparece no extrato e na API como uma linha própria em
GET /v1/transactions, comtype: "fee",feeKind: "boleto_unpaid"erelatedTransactionIdapontando para o boleto. - Estorno automático: se o boleto for pago depois de vencido, a taxa é devolvida junto com o crédito do pagamento — uma linha
type: "fee_reversal"com o mesmorelatedTransactionId. - O saldo pode ficar negativo por causa da taxa. Enquanto estiver negativo, saques são recusados por saldo insuficiente; o próximo pagamento recebido abate a diferença.
- O valor é o contratado para a sua conta — confira com o suporte. Sem taxa configurada, nada muda: o
expiredcontinua sem efeito financeiro.
Erros
| HTTP | error |
|---|---|
| 400 | "amountCents deve ser inteiro ≥ 100 (R$1,00 mínimo)." |
| 400 | "customer.name obrigatório." |
| 400 | "customer.document.number e customer.document.type obrigatórios." |
| 400 | "customer.document.type deve ser 'cpf' ou 'cnpj'. Recebido: '<valor>'." |
| 400 | "customer.email é obrigatório e deve ser válido." |
| 400 | "dueDate inválido (use YYYY-MM-DD)." |
| 400 | "customer.address é obrigatório para emitir boleto nesta conta." — e as variações por campo (customer.address.zipCode, customer.address.state, customer.phone…): a conta exige os dados completos do pagador; corrija o campo apontado. |
| 400 | "dueDate deve ser hoje ou uma data futura (YYYY-MM-DD)." |
| 400 | "Boleto em verificação: a emissão não confirmou. NÃO reenvie — consulte a transação <id> em instantes." — a emissão anterior não confirmou e o boleto pode existir; não emita outro para o mesmo pedido. |
| 400 | "Dados recusados pelo provedor: <campo> inválido. Corrija e reenvie. (<código>)" — o pagador ou a cobrança foi recusado na validação do provedor. <campo> diz o que corrigir (documento, e-mail, nome, endereço, vencimento, valor); <código> é estável, ex.: invalid_cpfCnpj. |
| 400 | "Limite de emissão de cobranças da conta atingido. Não reenvie; fale com o suporte. (issuance_limit)" — a conta chegou ao teto de emissão; reenviar não resolve. |
| 400 | "Emissão não permitida para esta conta no momento. Não reenvie; fale com o suporte. (account_restricted)" — a conta está impedida de emitir; reenviar não resolve. |
| 400 | "Boleto não está habilitado para esta conta." |
| 400 | "Boleto não disponível para esta conta no momento." — habilitação em andamento; tente mais tarde ou fale com o suporte. |
| 400 | "Valor acima do máximo permitido (R$ X.YY)." |
| 401 | "API key inválida ou revogada." |
| 403 | "Conta não está aprovada para uso da API." |
| 429 | "Limite de requisições atingido. Tente em 1 hora." |
| 500 | "Erro ao gerar boleto. Tente novamente." |
| 503 | "Boleto temporariamente indisponível. Tente novamente em instantes." — falha passageira: nada foi emitido, pode reenviar. |
Exemplos
curl -X POST https://api.coufai.com.br/v1/boleto \
-H "Authorization: Bearer $COUFAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amountCents": 5000,
"externalRef": "pedido-123",
"description": "Pedido 123",
"dueDate": "2026-09-30",
"customer": {
"name": "Maria Silva",
"email": "maria@exemplo.com",
"phone": "11999998888",
"document": { "number": "12345678901", "type": "cpf" },
"address": {
"street": "Rua das Flores", "number": "100", "district": "Centro",
"city": "São Paulo", "zipCode": "01310100", "state": "SP"
}
}
}'