Conciliação de pagamentos automatizada: como parar de fechar o caixa na mão
Como automatizar a conciliação com a API Pagnovo — externalId, consulta de transações, saldo por categoria, x-trace-id e a rotina que fecha o dia sozinha.
Equipe Pagnovo · 2026-08-06
Conciliar é responder uma pergunta simples: o que o sistema diz que recebi bate com o que realmente caiu? Quando isso é feito à mão, em planilha, o custo aparece de três formas — horas de trabalho, erro humano e a descoberta tardia de pedidos pagos que nunca foram entregues.
Este guia mostra como automatizar isso.
O erro que torna a conciliação difícil depois
A decisão mais importante acontece na criação da cobrança, não no fechamento do mês: enviar o
externalId.
POST /transactions/v2/purchase
{
"amount": 18990,
"externalId": "pedido-1042",
"description": "Pedido #1042"
}
O externalId é o identificador do pedido no seu sistema. Sem ele, você depende de guardar o ID
da Pagnovo em algum lugar — e se esse registro se perde (falha no meio da requisição, timeout, deploy
ruim), a transação vira órfã: existe dinheiro recebido sem pedido correspondente.
Com externalId, a busca funciona nos dois sentidos, e o mesmo endpoint aceita três chaves:
GET /transactions/:id
Ele resolve por ID da Pagnovo, pelo seu externalId ou pelo end2End do PIX. Isso cobre
praticamente qualquer cenário de investigação.
As três fontes que precisam bater
Uma conciliação honesta compara três coisas:
| Fonte | O que responde |
|---|---|
| Seu banco de dados | O que eu esperava receber |
| API da Pagnovo | O que foi efetivamente processado |
| Saldo da conta | Quanto está disponível de fato |
Se você só compara as duas primeiras, não percebe valores retidos. Por isso o terceiro ponto importa.
Saldo: nem tudo que entrou está disponível
GET /accounts/balance
A resposta separa o saldo em categorias — e essa separação é o que evita o susto no fim do mês:
- Disponível — pode ser sacado agora
- Em liquidação — já transacionado, ainda não liquidado
- Depósitos de garantia (collateral)
- Bloqueios cautelares
- Reservas de chargeback
Um erro comum é somar tudo e achar que é caixa. Não é: reserva de chargeback e bloqueio cautelar são valores que existem mas não podem ser usados. Sua conciliação deve tratar cada categoria separadamente, e seu fluxo de caixa deve olhar só para o disponível.
A rotina de conciliação
Um desenho que funciona bem na prática, rodando algumas vezes por dia:
// 1. Pedidos que criei mas ainda não confirmei
const pendentes = await db.orders.find({
status: 'PENDING',
createdAt: { $gte: ontem },
});
for (const pedido of pendentes) {
// 2. Pergunto à fonte da verdade, usando MEU identificador
const tx = await pagnovo.get(`/transactions/${pedido.externalId}`);
// 3. Reconcilio o estado
if (tx.status === 'APPROVED' && pedido.status !== 'PAID') {
await liberarPedido(pedido, tx); // webhook falhou — recupero aqui
}
if (['REJECTED', 'BLOCKED'].includes(tx.status)) {
await marcarFalha(pedido, tx.status);
}
if (tx.status === 'INCONSISTENT') {
await sinalizarParaHumano(pedido, tx); // não decida sozinho
}
}
Três princípios embutidos aí:
- A API é a fonte da verdade, não o seu banco.
- O job repara o que o webhook perdeu. Webhook é o caminho rápido; a conciliação é a rede.
INCONSISTENTnão se resolve automaticamente. Estado ambíguo vai para revisão humana — em dinheiro, chutar sai caro.
Os estados e o que fazer com cada um
| Status | Significado | Ação |
|---|---|---|
PENDING |
Aguardando pagamento | Manter em observação, respeitar expiração |
APPROVED |
Pago | Liberar pedido (idempotente) |
REJECTED |
Recusado | Encerrar, oferecer nova tentativa |
INCONSISTENT |
Divergência | Revisão manual |
BLOCKED |
Bloqueado | Revisão + contato com suporte |
Paginação: não perca registros no meio
Ao listar, a API usa paginação indexada em zero, com limite padrão de 20 e máximo de 100.
?page=0&limit=100
O erro clássico é ler só a primeira página e concluir que "tem 20 transações no período". Sempre percorra até a última página antes de fechar qualquer número.
x-trace-id: o que salva o seu suporte
Toda resposta da API inclui o header x-trace-id. Grave-o junto do registro da transação.
Quando surgir um caso do tipo "o cliente jura que pagou", você abre um chamado com o x-trace-id e o
time encontra exatamente aquela requisição nos logs — em vez de uma investigação por aproximação
usando horário e valor.
É uma linha de código no seu cliente HTTP que economiza horas depois.
Testando o fluxo de conciliação
No sandbox (sk_test_*), os valores geram resultados determinísticos — inclusive os incômodos:
| Valor | Estado gerado |
|---|---|
| R$ 10,00 | Aprovado |
| R$ 10,01 | Rejeitado |
| R$ 10,02 | Inconsistente |
| R$ 10,04 | Chargeback |
| R$ 10,05 | Estorno |
| R$ 10,06 | Bloqueado |
Ou seja: dá para testar de propósito o caminho do INCONSISTENT e do chargeback, que são justamente
os que quebram conciliação mal feita. O ambiente de teste permite 30 operações por dia.
Checklist
-
externalIdenviado em toda cobrança -
x-trace-idgravado com a transação - Job periódico varrendo pedidos pendentes
- Liberação de pedido idempotente (webhook e job não podem duplicar)
-
INCONSISTENTeBLOCKEDroteados para revisão humana - Paginação percorrida até o fim
- Saldo lido por categoria, não somado
- Alerta quando a fila de pendentes cresce fora do normal
Conheça nossa plataforma de Cobranças e a documentação da API. Precisa de ajuda para desenhar sua conciliação? Fale com o time.