Conciliação Bancária Automática
Documentação técnica do engine de conciliação que cruza confirmações do gateway com os pagamentos registrados no sistema.
Como Funciona (MVP)
Webhook do gateway ativo
↓
BankTransaction criada (status: UNMATCHED)
↓
ReconcilePaymentJob (Hangfire)
↓
Motor de Matching
├─ Regra 1: Gateway ID → MATCHED (100%)
├─ Regra 2: Valor exato + ≤3d → MATCHED (95%)
├─ Regra 3: Valor exato + ≤7d → MATCHED, flag revisar (80%)
└─ Regra 4: Valor ±2% + ≤3d → DIVERGENT (60%)
↓
UNMATCHED / DIVERGENT → Fila de revisão manualFontes de Dados Bancários
Confirmação Automática via Gateway (MVP)
Quando o gateway ativo do tenant envia a confirmação de pagamento, o sistema:
- Atualiza a fatura para
PAID - Cria uma
BankTransactionvirtual com ogatewayId - Executa a Regra 1 imediatamente (100% de confiança)
Esse fluxo cobre automaticamente todos os pagamentos processados pelo gateway configurado (PIX, cartão, boleto).
Import de Extrato OFX (Roadmap — pós-MVP)
Versão futura
A importação manual de extratos bancários em formato OFX/OFXXML será disponibilizada em versão pós-MVP. No MVP, a conciliação cobre apenas pagamentos confirmados via gateway.
No futuro, o tenant poderá fazer upload de um arquivo .ofx exportado pelo banco para conciliar pagamentos realizados fora do gateway (dinheiro, transferência direta, etc.).
Open Finance (Roadmap V2)
Conexão direta com a API do banco via certificado digital, eliminando a necessidade de qualquer importação manual.
Motor de Matching
O job ReconcilePaymentJob aplica as regras em ordem decrescente de confiança. A primeira regra que encontrar um match é utilizada.
Regra 1 — Gateway ID (confiança: 100%)
// A descrição da transação bancária contém o ID do gateway
transaction.Description.Contains(payment.GatewayId)Aplicada a transações confirmadas pelo gateway ativo. Match definitivo, sem necessidade de revisão.
Regra 2 — Valor exato + data próxima (confiança: 95%)
transaction.Amount == payment.Amount
&& Math.Abs((transaction.Date - payment.PaidAt).TotalDays) <= 3Match automático. Comum para transferências bancárias e pagamentos à vista.
Regra 3 — Valor exato + período estendido (confiança: 80%)
transaction.Amount == payment.Amount
&& Math.Abs((transaction.Date - payment.PaidAt).TotalDays) <= 7Match automático com flag review_suggested = true. Aparece na fila de revisão pendente, mas não bloqueia o fluxo.
Regra 4 — Valor aproximado (confiança: 60%)
var diff = Math.Abs(transaction.Amount - payment.Amount) / payment.Amount;
diff <= 0.02
&& Math.Abs((transaction.Date - payment.PaidAt).TotalDays) <= 3Status DIVERGENT. Revisão manual obrigatória. Comum em cobranças com taxa de conveniência ou IOF.
Revisão Manual
Listar pendentes de revisão
GET /bank-transactions?status=UNMATCHED,DIVERGENT&from=2026-05-01&to=2026-05-31
Response 200:
{
"items": [
{
"id": "uuid",
"date": "2026-05-10",
"amount": 350.00,
"description": "PIX RECEBIDO FULANO DE TAL",
"status": "UNMATCHED",
"suggestions": [
{
"paymentId": "uuid",
"invoiceNumber": "CLI-2026-00098",
"patientName": "Maria Silva",
"amount": 350.00,
"paidAt": "2026-05-10",
"confidence": 0.95
}
]
}
],
"total": 14
}Conciliar manualmente
POST /bank-transactions/:txId/reconcile
{
"paymentId": "uuid",
"notes": "Confirmado via extrato PDF — mesma operação"
}Ignorar transação
Para transações sem correspondência no sistema (ex: estorno interno):
POST /bank-transactions/:txId/ignore
{
"reason": "Estorno interno processado fora do sistema"
}Contas Bancárias
Cadastro
POST /bank-accounts
{
"name": "Conta Principal",
"bankCode": "341",
"agency": "1234",
"account": "56789-0",
"type": "CHECKING"
}Listagem
GET /bank-accounts
Response 200:
[
{
"id": "uuid",
"name": "Conta Principal",
"bankCode": "341",
"bankName": "Itaú Unibanco",
"balance": {
"reconciled": 48500.00,
"unreconciled": 2300.00
}
}
]Relatório de Conciliação
GET /reports/reconciliation?from=2026-05-01&to=2026-05-31&bankAccountId=uuid
Response 200:
{
"period": { "from": "2026-05-01", "to": "2026-05-31" },
"bankAccountName": "Conta Principal",
"totalTransactions": 312,
"matched": 298,
"divergent": 8,
"unmatched": 6,
"ignored": 0,
"matchRate": "95.5%",
"totalCredited": 48500.00,
"totalReconciled": 46200.00,
"pendingAmount": 2300.00,
"divergentAmount": 180.00
}Alertas Automáticos
| Evento | Destinatário | Canal |
|---|---|---|
| Transação sem match após 48h | Admin | E-mail + notificação in-app |
| Taxa de conciliação abaixo de 90% no período | Owner + Admin | |
| Valor divergente acima de R$ 100,00 | Admin | Notificação in-app |
Endpoints
| Método | Endpoint | Papel mínimo | Descrição |
|---|---|---|---|
GET | /bank-accounts | Admin | Listar contas bancárias |
POST | /bank-accounts | Admin | Cadastrar conta bancária |
GET | /bank-transactions | Admin | Listar transações |
GET | /bank-transactions/:id | Admin | Detalhe da transação |
POST | /bank-transactions/:id/reconcile | Admin | Conciliar manualmente |
POST | /bank-transactions/:id/ignore | Admin | Ignorar transação |
GET | /reports/reconciliation | Admin | Relatório de conciliação |
Segurança
- Apenas roles
AdmineOwnertêm acesso ao módulo de conciliação - Toda ação manual é registrada no audit log com
userId, timestamp e motivo externalIdgarante idempotência no processamento das confirmações do gateway