Skip to main content
Nordlys logo, a drawing of two gray mountains with green northern lights in the background @phpeterle Blog

Back to all posts

O que metrologia me ensinou sobre gateways de pagamento

Published on by Pedro Peterle · 19 min read

Sou formado em engenharia de produção, e uma das matérias base do curso é metrologia, a ciência das medições. Na época parecia a disciplina mais burocrática da grade: norma, certificado, laboratório acreditado, planilha de incerteza. Hoje trabalho com pagamentos na Woovi, e várias decisões de arquitetura que a gente toma são, no fundo, o mesmo problema que a metrologia resolve há décadas.

A ligação é a seguinte: perguntar “esse pagamento foi confirmado?” é fazer uma medição. Você não observa o fato diretamente, observa o que algum instrumento te reporta. E quando existe um intermediário entre a sua aplicação e a fonte de verdade (no Pix, o Banco Central), você está na mesma situação de um laboratório que calibra o instrumento contra um padrão, que foi calibrado contra outro padrão, que foi calibrado contra outro.

Neste post vou explicar como a metrologia trata erro e calibração, e depois usar esses conceitos para olhar a arquitetura de um sistema de pagamentos, principalmente o que muda quando o gateway que você usa não tem conexão direta com o Bacen.

Erro de medição

O primeiro conceito é que valor verdadeiro é inatingível. Você nunca mede a massa de um objeto, você mede o que a balança indica, que é o valor verdadeiro somado a um erro que você não conhece.

valor indicado = valor verdadeiro + erro

Como o erro é desconhecido, o que se faz na prática é estimar um intervalo onde o valor verdadeiro provavelmente está. Isso é a incerteza de medição, e é por isso que um certificado de calibração nunca diz “a peça mede 10 mm”, e sim algo como:

10,002 mm ± 0,003 mm (k = 2, ~95% de confiança)

O ± 0,003 faz parte do resultado. Sem ele, o 10,002 não permite decidir nada, porque você não sabe se a peça está dentro ou fora da tolerância do projeto.

Os erros se dividem em dois tipos, e essa separação importa bastante:

  • Erro sistemático: sempre na mesma direção. Uma balança descalibrada que marca 2 g a mais em toda pesagem. Dá para corrigir, se você conhecer o valor.
  • Erro aleatório: varia a cada medição, ora para cima, ora para baixo. É ruído. Não dá para corrigir, mas dá para reduzir repetindo a medição e tirando a média.

Tratar erro sistemático como se fosse aleatório é o erro clássico: você repete a medição mil vezes e a média converge com ótima precisão para o valor errado.

A cadeia de rastreabilidade

Como você sabe que a sua balança está certa? Comparando com um padrão. E como você sabe que o padrão está certo? Comparando com um padrão melhor. Isso se repete até chegar na definição do SI.

Esse encadeamento tem nome: cadeia de rastreabilidade metrológica. É uma sequência ininterrupta de calibrações ligando o instrumento que está no chão de fábrica até o padrão primário.

flowchart TB
  SI["Definição SI<br/>(BIPM)"]
  NMI["Padrão nacional<br/>(Inmetro)"]
  Lab["Laboratório acreditado<br/>(RBC)"]
  Interno["Padrão interno<br/>da empresa"]
  Inst["Instrumento de trabalho<br/>(chão de fábrica)"]

  SI -->|u1| NMI
  NMI -->|u2| Lab
  Lab -->|u3| Interno
  Interno -->|u4| Inst

Cada seta é uma calibração, e cada calibração adiciona incerteza. Não existe elo que melhore a precisão do anterior: o melhor que um elo faz é degradar pouco.

Como o erro se acumula

Para contribuições independentes, a incerteza combinada é a soma em quadratura:

u_c = sqrt(u1² + u2² + u3² + u4²)

A consequência prática disso é que a maior contribuição domina o resultado. Com u1 = 0,1, u2 = 0,1, u3 = 0,1 e u4 = 1,0, a combinada dá 1,015. Zerar completamente os três primeiros elos levaria o total para 1,0. Todo o esforço, e o ganho é de 1,5%.

Isso vale para erros independentes. Se as contribuições forem correlacionadas (todos os elos usando o mesmo padrão enviesado, ou todos medindo no mesmo ambiente com temperatura fora da faixa), elas somam linearmente:

u_c = u1 + u2 + u3 + u4

O acúmulo fica muito pior. Erro correlacionado é o problema mais chato da cadeia, porque você acha que está somando ruído quando na verdade está somando bias.

Existe uma regra prática de calibração industrial chamada TUR (test uncertainty ratio): o padrão usado precisa ser pelo menos 4 vezes mais preciso que a tolerância que você quer garantir. Para tolerância de ± 0,1 mm, o padrão precisa de incerteza melhor que 0,025 mm. Medir com precisão parecida com a tolerância é praticamente não medir.

Calibração não elimina erro

Calibrar não deixa o instrumento perfeito. Calibrar é levantar o erro dele em pontos específicos da faixa e, quando dá, corrigir o bias. Um instrumento calibrado não é um que não erra, é um que erra de forma conhecida e documentada.

Isso muda três coisas na operação: você sabe em qual faixa confiar no instrumento, sabe que ele deriva com o tempo e precisa voltar para o laboratório, e sabe se o erro atual é aceitável para a decisão que você vai tomar com aquele número.

O elo mais fraco

Vale registrar uma coisa antes de ir para pagamentos, porque não é sobre paquímetro. O que está descrito acima é um modelo de sistema em série, e ele reaparece com outros nomes em quase toda disciplina de engenharia de produção:

  • Na Teoria das Restrições, a capacidade da linha é a capacidade do gargalo. Investir na estação mais rápida não aumenta um item na saída.
  • Em gestão de projetos, o prazo é o caminho crítico. Adiantar tarefa fora dele não antecipa a entrega.
  • Em cadeia de suprimentos, a fábrica para por causa do fornecedor que quebrou, não da média dos fornecedores.
  • Em confiabilidade, componentes em série têm disponibilidade igual ao produto das disponibilidades, sempre menor que a do pior.
  • Em rendimento de processo, o rolled throughput yield é o produto dos rendimentos de cada etapa.

Em todos esses casos a matemática tem a mesma cara: você compõe as contribuições de cada elo (somando incertezas, multiplicando disponibilidades, multiplicando rendimentos) e o resultado é sempre pior do que qualquer elo isolado. Composição em série nunca melhora o todo.

Daí sai a parte que interessa na prática: como o pior elo domina, otimizar qualquer outro é desperdício. Em produção isso se aprende cedo porque errar custa caro, a fábrica que investiu na estação errada continua com o mesmo throughput e um capital a menos.

A força do sistema é a força do elo mais fraco. O trabalho de engenharia é descobrir qual é esse elo, e isso é uma pergunta de medição, não de opinião.

Gateways de pagamento

Trocando “medição” por “estado de um pagamento” e “cadeia de rastreabilidade” por “cadeia de liquidação”, a estrutura é a mesma.

No Pix, a fonte de verdade é o SPI (Sistema de Pagamentos Instantâneos), operado pelo Banco Central. Um pagamento está liquidado quando o SPI diz que está. Não quando o seu backend diz, não quando o gateway diz.

Só que nem todo mundo fala com o SPI. Para conectar direto é preciso ser participante direto: autorização do Bacen, infraestrutura na RSFN, certificados ICP-Brasil, atender aos requisitos de disponibilidade e de compliance da regulação. É caro, é demorado, e a maior parte das empresas não tem como fazer isso.

Então o mercado se organizou em camadas. Quem não é participante direto se pluga em quem é.

flowchart TB
  Bacen["Banco Central<br/>SPI / DICT"]
  Direto["Participante direto<br/>(instituição autorizada)"]
  Indireto["Participante indireto / PSP<br/>(liquida via o direto)"]
  Gw["Gateway / orquestrador<br/>(camada de API)"]
  App["Sua aplicação"]

  Bacen -->|RSFN| Direto
  Direto -->|contrato + API| Indireto
  Indireto -->|API| Gw
  Gw -->|webhook + API| App

É o mesmo desenho da cadeia de rastreabilidade, e vale a mesma regra: nenhum elo melhora a garantia do anterior.

O que muda de uma cadeia para a outra é o que se acumula. Na metrologia acumula incerteza de medição. Aqui acumulam quatro coisas ao mesmo tempo: latência (cada hop custa tempo de rede), indisponibilidade (cada hop pode cair sozinho), divergência de estado (cada hop tem sua própria cópia do estado) e risco regulatório (cada hop responde a um contrato e a um regulador diferentes). As duas primeiras todo mundo considera. As duas últimas são as que costumam quebrar sistema em produção.

Disponibilidade composta

Se cada elo tem disponibilidade independente, a disponibilidade fim a fim é o produto delas:

A_total = A1 × A2 × A3 × A4

Com números plausíveis:

CadeiaCálculoDisponibilidadeIndisponibilidade/mês
Direto no participante autorizado99,95%99,95%~22 min
Participante + PSP indireto99,95% × 99,9%99,85%~65 min
Participante + PSP + gateway99,95% × 99,9% × 99,9%99,75%~108 min
Participante + PSP + gateway + orquestrador99,95% × 99,9% × 99,9% × 99,9%99,65%~151 min

Cada camada adicional custa por volta de 43 minutos de indisponibilidade por mês, mesmo que cada uma delas pareça excelente isoladamente. É o mesmo fenômeno do acúmulo de incerteza: você não consegue ser mais confiável que o produto dos seus elos.

O pior elo domina aqui também. Um gateway com 99,5% na frente de um participante com 99,95% resulta em 99,45%. Nesse cenário, melhorar a sua aplicação de 99,99% para 99,999% não muda nada no número que o seu cliente enxerga. É a estação rápida sendo otimizada enquanto o gargalo continua parado.

A conta acima assume falhas independentes. Se dois gateways diferentes liquidam pelo mesmo participante direto, eles não são redundantes: quando o participante cai, os dois caem junto. É exatamente o erro correlacionado da metrologia, que soma linear em vez de em quadratura.

O estado não é o mesmo em todo lugar

Esse é o problema mais silencioso da cadeia. Cada elo guarda uma cópia do estado do pagamento, e essas cópias não mudam ao mesmo tempo.

sequenceDiagram
  participant SPI as SPI (Bacen)
  participant PD as Participante direto
  participant GW as Gateway
  participant App as Sua aplicação

  SPI->>PD: liquidado em T0
  Note over PD: estado atualizado em T0 + 200ms
  PD->>GW: notificação
  Note over GW: estado atualizado em T0 + 900ms
  GW-->>App: webhook
  Note over App: estado atualizado em T0 + 2s<br/>(ou nunca, se o webhook falhar)

Entre T0 e o momento em que a sua aplicação atualiza existe uma janela onde você tem uma medição desatualizada sem saber disso. Se o webhook se perder, essa janela não fecha.

Os modos de falha dessa janela são conhecidos por quem trabalha com pagamento:

  • Webhook perdido: o pagamento liquidou, o cliente pagou, e o seu sistema nunca soube. O cliente aparece no suporte com o comprovante na mão.
  • Webhook duplicado: a mesma notificação chega duas vezes por retry. Sem idempotência, você credita duas vezes.
  • Webhook fora de ordem: chega CONFIRMED depois de EXPIRED, porque foram por rotas diferentes.
  • Timeout ambíguo: você pediu a criação de uma cobrança, deu timeout, e não sabe se ela existe do outro lado. É o pior tipo de erro, o que não te diz se aconteceu.

Repare que nada disso é erro aleatório. É erro sistemático. Consultar o mesmo gateway de novo não ajuda, porque se ele tem o estado errado ele vai devolver o estado errado de forma bem consistente. Para corrigir bias é preciso medir contra um padrão de nível superior.

Regulatório e compliance

Existe um risco em metrologia que não é técnico: o laboratório que calibra o seu padrão pode perder a acreditação. Da noite para o dia todos os certificados que ele emitiu ficam questionáveis e a sua cadeia de rastreabilidade fica inválida, mesmo com os instrumentos fisicamente perfeitos.

Na cadeia de pagamentos acontece a mesma coisa, e essa é a categoria de risco que menos aparece nas comparações de gateway:

  • Quem responde ao Bacen é o participante direto. Se ele sofre sanção, tem a autorização suspensa ou entra em regime especial, todo mundo pendurado nele para de operar. Você não fez nada e mesmo assim está fora do ar.
  • O contrato que sustenta a sua operação não é seu. O acordo entre o participante direto e o PSP intermediário pode mudar sem você participar da conversa. Uma mudança de política de risco em um elo que você nem conhece derruba o seu fluxo.
  • Requisito novo desce a cadeia com atraso. Uma exigência do Bacen chega ao participante direto, que repassa ao PSP, que repassa ao gateway, que precisa expor aquilo na API para você conseguir cumprir. Cada tradução perde informação, e o prazo de adequação continua sendo o original.
  • Compliance vira caixa preta. Quando o seu cliente é bloqueado por análise de risco, quem tomou a decisão? Em uma cadeia de quatro elos, descobrir isso vira um processo de dias por email, sobre uma regra que afeta diretamente a sua receita.
  • A superfície de dados aumenta. Dados de transação e dados pessoais passam por mais um terceiro. Para LGPD, cada intermediário é mais um operador no fluxo, mais um contrato, mais um lugar para auditar e mais um ponto de vazamento possível.
  • A custódia do dinheiro fica confusa. Entre a liquidação e o repasse para você, o recurso fica em conta de quem exatamente? Em cadeia longa a resposta costuma ser “de alguém no meio”, e o risco de crédito desse elo é seu.

Calibrando o sistema

A resposta da metrologia para “meu instrumento tem erro” nunca foi jogar o instrumento fora. Foi conhecer o erro, corrigir o bias, monitorar a deriva e recalibrar de tempos em tempos. Aqui funciona igual: o problema não é usar gateway, é usar sem medir.

Escolha o padrão de referência

Você precisa definir qual fonte é a verdade do seu sistema, e ela não pode ser o seu próprio banco. Na prática o mais próximo que dá para chegar é o extrato do participante direto, que é o elo mais perto do SPI ao qual você tem acesso.

Todo o resto (resposta de API, webhook, cache) é medição, está sujeita a erro e precisa ser conferida contra esse padrão periodicamente.

Reconciliação é calibração

Reconciliar não é tarefa contábil, é a calibração do sistema. Ela responde exatamente a pergunta metrológica: qual o erro atual da minha medição em relação ao padrão?

flowchart LR
  Extrato["Extrato do participante<br/>(padrão de referência)"]
  DB["Estado no seu banco<br/>(instrumento)"]
  Diff["Diff"]
  Metric["Métrica de divergência<br/>+ alerta"]

  Extrato --> Diff
  DB --> Diff
  Diff --> Metric

E o resultado precisa virar número, do mesmo jeito que um certificado de calibração vira número:

/metrics
# HELP payments_reconciliation_divergence_total Divergências entre estado local e extrato
# TYPE payments_reconciliation_divergence_total counter
payments_reconciliation_divergence_total{type="missing_locally",provider="gw_a"} 12
payments_reconciliation_divergence_total{type="missing_upstream",provider="gw_a"} 0
payments_reconciliation_divergence_total{type="amount_mismatch",provider="gw_a"} 1
# HELP payments_state_lag_seconds Atraso entre liquidação na origem e atualização local
# TYPE payments_state_lag_seconds histogram
payments_state_lag_seconds_bucket{le="1",provider="gw_a"} 8420
payments_state_lag_seconds_bucket{le="5",provider="gw_a"} 9910
payments_state_lag_seconds_bucket{le="30",provider="gw_a"} 9998
payments_state_lag_seconds_bucket{le="+Inf",provider="gw_a"} 10000

Com o label provider você consegue comparar provedores entre si e alertar quando um deles começa a derivar. Sem essas métricas você não sabe o erro do instrumento, apenas confia nele.

Webhook não é fonte de verdade

Webhook é push: sem garantia de entrega, de ordem ou de unicidade. Ele serve para reduzir latência, avisando que alguma coisa mudou. A correção vem da consulta e da reconciliação.

async function onWebhook(event: GatewayEvent) {
// sem validar assinatura, o sensor aceita qualquer entrada
if (!verifySignature(event)) return reject()
// idempotência pela chave do provedor, não por id gerado localmente
if (await alreadyProcessed(event.endToEndId)) return ack()
// não confia no payload: reconsulta o estado na origem
const state = await gateway.getCharge(event.chargeId)
// transição só avança, nunca regride
await applyStateTransition(event.chargeId, state)
return ack()
}

Os três pontos que mais evitam dor de cabeça:

  • Idempotência pela chave de negócio do provedor. No Pix o endToEndId é estável ao longo de toda a cadeia, então ele funciona como chave mesmo se o pagamento passar por vários elos.
  • Reconsultar em vez de confiar no corpo do webhook, que pode estar defasado até em relação ao próprio gateway que o enviou.
  • Máquina de estados monotônica. Uma cobrança que já está CONFIRMED não volta para PENDING porque chegou um evento antigo. É o equivalente a rejeitar leitura fora da faixa do instrumento.

Meça cada elo separadamente

Em metrologia, decompor a incerteza serve para saber qual contribuição atacar. Aqui é a mesma coisa: medir só a latência fim a fim não diz onde investir.

Instrumentando por hop, com provider como label, aparecem coisas como “o gateway responde em 80 ms mas o participante atrás dele leva 1,2 s”. Sem essa decomposição você não sabe qual é o elo mais fraco, e sem saber qual é o elo mais fraco toda otimização vira aposta.

Faça a conta antes de escolher

Antes de assinar com um gateway, dá para fazer o mesmo cálculo que um metrologista faria, que é verificar se a incerteza total cabe na tolerância:

  • Esse provedor é participante direto? Se não for, quantos elos existem entre ele e o SPI? Vale perguntar isso explicitamente, porque é comum um produto se descrever como “conexão Pix” sem deixar claro que liquida por três camadas.
  • Qual disponibilidade eu preciso entregar para o meu cliente?
  • Multiplicando os SLAs de toda a cadeia, eu chego nesse número?
  • Quem é o participante direto na ponta? É o mesmo dos meus outros provedores?
  • O que esse intermediário me entrega que compensa os elos que ele adiciona?

A lógica do TUR se aplica bem aqui. Se você precisa entregar 99,9% e escolhe um caminho que entrega 99,9% no melhor cenário, é o mesmo que medir tolerância de 0,1 mm com um instrumento de 0,1 mm de incerteza. Precisa de folga.

Redundância só vale se for independente

Ter dois gateways parece redundância, mas se os dois liquidam pelo mesmo participante direto o modo de falha é comum. Redundância de verdade exige caminhos que separam o mais perto possível da origem.

flowchart TB
  SPI["SPI"]
  P1["Participante A"]
  P2["Participante B"]
  G1["Gateway 1"]
  G2["Gateway 2"]
  App["Sua aplicação"]

  SPI --> P1
  SPI --> P2
  P1 --> G1
  P2 --> G2
  G1 --> App
  G2 --> App

Se os dois caminhos convergem em um único participante antes do Bacen, você tem duas integrações para manter e um ponto único de falha.

O custo de manter vários provedores

Essa é a saída mais comum de quem usa gateway. Como cada provedor sozinho não entrega a disponibilidade necessária, contrata-se dois ou três e coloca-se uma camada de roteamento na frente, que troca de rota quando um começa a falhar. Em confiabilidade isso é redundância paralela, e funciona: com dois caminhos independentes de 99,75%, a indisponibilidade dos dois ao mesmo tempo cai para 0,0006%.

O problema é que a conta de disponibilidade melhora e a de complexidade piora, e a segunda ninguém coloca na planilha antes de decidir:

  • Cada provedor tem o seu modelo. Nomes de estado diferentes, códigos de erro diferentes, formato de webhook diferente, política de retry diferente. Você acaba escrevendo uma camada de tradução para um estado interno canônico, e essa camada vira o lugar onde os bugs aparecem.
  • A reconciliação multiplica. Cada provedor tem seu extrato, seu horário de fechamento e seu jeito de identificar a transação. Reconciliar dois é mais que o dobro do trabalho de reconciliar um, porque agora existe o caso de a cobrança ter sido criada em um e paga pelo outro.
  • O roteamento precisa de estado. Decidir qual provedor usar exige saber a saúde de cada um em tempo real, ter health check, circuit breaker e critério de volta. Roteador mal calibrado derruba tráfego bom ou insiste em rota morta.
  • O failover em cima de operação em andamento é o caso difícil. Trocar de rota é simples para uma cobrança nova. Para uma cobrança já criada no provedor que caiu, não é: ela existe lá, pode ser paga a qualquer momento e continua sendo responsabilidade sua.
  • A superfície de teste cresce junto. Sandbox de cada provedor, comportamento de cada um em timeout, e o cenário de failover, que é justamente o mais difícil de reproduzir e por isso quase nunca é testado.

O resultado é que você troca um problema de confiabilidade por um problema de engenharia, e passa a manter internamente algo parecido com um orquestrador de pagamentos. Para operação grande isso se paga. Para time pequeno costuma sair mais caro do que aparenta, e é bom notar que boa parte desse trabalho existe para compensar a instabilidade que os elos extras introduziram.

Vale a mesma ressalva do erro correlacionado: dois provedores só melhoram a disponibilidade se forem independentes de verdade. Se ambos liquidam pelo mesmo participante direto, você pagou todo esse custo de complexidade e continua com um ponto único de falha.

Resumo do paralelo

MetrologiaPagamentos
Valor verdadeiroEstado no SPI
MediçãoResposta de API ou webhook do gateway
Cadeia de rastreabilidadeCadeia de liquidação (Bacen → direto → PSP → gateway)
Cada elo adiciona incertezaCada elo adiciona latência, queda e risco
Erro sistemáticoEstado divergente, webhook perdido, defasagem
Erro aleatórioTimeout esporádico, jitter de rede
Erros correlacionados somam linearmenteGateways que compartilham o mesmo participante direto
Calibração periódicaReconciliação contra o extrato da origem
Certificado com incerteza declaradaSLA composto, medido por provedor
Laboratório perde a acreditaçãoParticipante direto sancionado ou te desligando
TUR 4:1Folga entre o SLA da cadeia e o que você promete
Gargalo define a capacidade da linhaElo mais fraco define o SLA que você entrega

Conclusão

A variável que mais mexe no resultado final é o número de elos entre você e o SPI, e ela costuma ser decidida sem análise nenhuma. Escolhe-se um provedor pela documentação, pela taxa ou por indicação, e a topologia da cadeia vem junto no pacote sem ninguém perguntar.

Vale separar duas coisas aqui. Ser participante direto você provavelmente não vai ser, porque exige autorização, infraestrutura na RSFN e um custo de compliance que só se paga em escala grande. Mas saber se o seu provedor é um, e o que existe atrás dele quando não é, é pergunta de contrato e não de engenharia. Está ao alcance de qualquer empresa fazer.

Voltando à conta: cada camada intermediária custa cerca de 43 minutos de indisponibilidade por mês, uma cópia a mais do estado do pagamento para divergir, um hop a mais de rede e fila em cima do tempo de confirmação, e mais um contrato entre você e quem responde ao Bacen. Nenhuma delas devolve nada em precisão ou em velocidade, porque composição em série não melhora o todo. Elas se pagam por outras coisas, como conveniência de integração, meios de pagamento adicionais ou antifraude embutido, e é exatamente essa troca que precisa ser explícita na hora de escolher.

Reparei que essa troca costuma ser paga duas vezes. Primeiro na cadeia mais longa, depois na multiplicação de provedores que se contrata para compensar a instabilidade que ela trouxe. Roteamento, tradução de estado, reconciliação por provedor e teste de failover são código que só existe por causa dos elos extras, e mantê-lo é trabalho recorrente de um time que provavelmente preferia estar resolvendo outra coisa. Encurtar a cadeia resolve o mesmo problema pelo outro lado, sem código nenhum.

Quando a cadeia longa for a opção certa, o resto do post vale igual: reconcilie contra a fonte mais próxima da origem que você alcançar, meça a divergência por provedor e prometa ao seu cliente menos do que o SLA composto da sua cadeia.

O modelo que descrevi aqui não é da metrologia, ela só é uma das áreas que o formaliza bem. Gargalo, caminho crítico, cadeia de rastreabilidade e cadeia de liquidação são o mesmo objeto visto por janelas diferentes, e em todos eles a força do sistema é a força do elo mais fraco. Vale mais aprender a reconhecer esse padrão do que decorar as fórmulas de cada área isoladamente, porque quando você troca de contexto o modelo vai junto.

Referências