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:

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

  1. A API é a fonte da verdade, não o seu banco.
  2. O job repara o que o webhook perdeu. Webhook é o caminho rápido; a conciliação é a rede.
  3. INCONSISTENT nã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


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.