Roteamento
Fluxos de roteamento
Como o construtor visual decide por qual adquirente cada transacao passa, e como testar antes de publicar.
Um fluxo decide o caminho de cada transacao: qual adquirente tenta primeiro, quando passar por antifraude, quando dividir o valor e o que fazer na recusa.
Fluxos sao desenhados no painel, arrastando etapas. Esta pagina explica o modelo por tras do desenho - util para quem vai montar o fluxo e essencial para quem vai criar fluxos por API.
O modelo
Um fluxo e um grafo aciclico de nos ligados por arestas. Cada no tem portas de saida nomeadas, e cada porta leva a uma proxima etapa.
Gatilho ──▶ Faixa de ticket ──alto──▶ Antifraude ──aprovar──▶ Adquirente Y ──▶ Aprovar
│ │
│ recusar ──────────────────────────────▶ Recusar
└──demais──▶ Adquirente X ──aprovado──▶ Aprovar
Por que aciclico: um ciclo no caminho de autorizacao poderia girar indefinidamente enquanto o comprador espera. Para repetir uma cobranca em outra data existe o no de Retentativa, que agenda em vez de voltar no grafo.
Tipos de no
| Grupo | No | O que faz | Portas |
|---|---|---|---|
| Inicio | Gatilho | Evento que inicia o fluxo | next |
| Logica | Condicao | Divide em verdadeiro ou falso | true, false |
| Logica | Multiplos caminhos | Avalia casos em ordem | ids dos casos, default |
| Logica | Definir variavel | Guarda um valor para as proximas etapas | next |
| Risco | Antifraude | Consulta o provedor e ramifica | approve, review, decline, error |
| Risco | Validacao de cartao | Confere o cartao sem cobrar (Zero Auth) | valid, invalid, unavailable, error |
| Risco | Autenticacao 3DS | Autentica o portador | authenticated, not_authenticated, unavailable |
| Risco | Revisao manual | Pausa ate a decisao de um analista | approved, declined |
| Processamento | Rotear | Escolhe o conector (cartao nao troca) | approved, declined, error |
| Processamento | Capturar | Captura o valor autorizado | captured, failed |
| Processamento | Split | Divide entre recebedores | next |
| Cobranca | Retentativa | Reagenda conforme a politica | scheduled, exhausted |
| Cobranca | Aguardar | Pausa e retoma depois do prazo | next |
| Integracao | Webhook | Emite flow.notification | next |
| Fim | Aprovar / Recusar | Encerra o fluxo | nenhuma |
Cada porta aceita uma ligacao. Duas setas saindo de "Aprovado" tornariam o
fluxo ambiguo, e o motor nao teria como escolher. E toda porta precisa de
destino, inclusive error: uma porta solta nao e "nada acontece", e o
pagamento terminaria sem decisao explicita.
No painel, um duplo clique na etapa abre a configuracao no painel lateral. As etapas que dependem de parceiro (antifraude, rota, validacao de cartao, 3DS) escolhem o provedor e a conta ali mesmo, com cadastro de chaves e Testar conexao - ver Conectores.
Antifraude: score ou recomendacao
O score de todo provedor e normalizado para 0 a 100 (100 = risco maximo),
para que trocar Konduto por ClearSale nao exija recalibrar o fluxo. O no decide
de um de dois jeitos (decisionMode):
| Modo | Quem decide | Configuracao |
|---|---|---|
score | As faixas do no: aprovar abaixo de X, recusar a partir de Y | approveBelow, declineAbove |
recommendation | A recomendacao do provedor (aprovar/revisar/recusar) | - |
Quando o provedor decide sem devolver score (a ClearSale decide por
status), vale a recomendacao dele nos dois modos - o Minstrel nunca inventa um
numero. Timeout (timeoutMs) ou provedor fora do ar saem pela porta error;
ligue-a a uma revisao manual para nao perder a venda.
Validacao de cartao (Zero Auth)
O no Validacao de cartao (zero_auth) usa a autorizacao de valor zero
(Zero Auth) para conferir se o cartao esta ativo. Nao cobra, nao reserva
limite e nao avisa o portador. Serve para barrar um cartao morto antes de
gastar uma tentativa de venda, por exemplo na primeira cobranca de uma
assinatura.
| Porta | Quando sai por ela | Sugestao |
|---|---|---|
valid | Valido: o emissor confirmou que o cartao esta ativo. | Seguir para a rota. |
invalid | Invalido: o emissor disse que o cartao nao serve. | Recusar. Nao envie ao emissor. |
unavailable | Indisponivel: bandeira sem suporte, recurso desligado na conta ou token de outra conta. | Seguir sem validar, se o seu risco permitir. |
error | Falha tecnica (timeout, parceiro fora do ar). | Seguir sem validar ou desviar para uma revisao manual. |
Separar invalid de unavailable e a razao de o no existir: so o primeiro
justifica recusar a venda. unavailable nao diz nada sobre o cartao, e um
servico fora do ar ou nao habilitado na conta nunca deve virar "cartao ruim".
Enviar ao emissor um cartao invalid so geraria outra recusa, que ainda conta
nos programas de retentativa das bandeiras.
| Campo | Padrao | Efeito |
|---|---|---|
Conta (connectorAccountId) | A conta onde o cartao foi salvo | Opcional. O token da Cielo so vale na conta que o criou, entao deixar em branco e quase sempre o certo. Outra conta, que nao e a do cartao, sai por unavailable. |
reuseWithinDays | 30 (de 0 a 365) | Reaproveita uma validacao valid recente do mesmo cartao, sem consultar de novo. 0 valida sempre. |
O reaproveitamento existe porque o Zero Auth conta nos programas de
retentativa das bandeiras e pode ter custo no adquirente: validar o mesmo
cartao a cada pagamento seria pagar, e arriscar tarifa, por uma resposta que
ja se tem. So uma validacao valid e reaproveitada.
No editor, so aparecem as contas com a validacao de cartao ligada
(Plugins, conta, Recursos - ver
Conectores). Quando a validacao e
aprovada num cartao salvo, ela abre a cadeia da rede (IssuerTransactionId e,
na Mastercard, o TLID) como se fosse uma primeira transacao: as cobrancas sem o
cliente que vierem depois partem dela.
Exemplo: validar so a primeira compra do cliente.
Gatilho ──▶ Condicao: customer.is_first_purchase = true
│
├── true ──▶ Validacao de cartao ──valid──▶ Rotear ──approved──▶ Aprovar
│ │
│ └── invalid ──▶ Recusar
└── false ──▶ Rotear
As portas unavailable e error tambem precisam de destino, como qualquer
porta: no exemplo acima, ligue-as a um segundo Rotear para seguir sem validar.
O resultado fica disponivel para as regras seguintes em card.verification_status
e card.verified_days_ago (veja
Campos disponiveis nas regras). Para validar o
cartao na hora de salva-lo, sem fluxo, use o parametro verify descrito em
Clientes e grupos.
Captura imediata ou adiada
O no Capturar tem dois modos. Em immediate (padrao), captura assim que a
autorizacao e aprovada. Em delayed, agenda a captura para delayHours horas
depois (captureScheduledAt) e quem a executa e o worker, nao o fluxo: o
pagamento fica authorized ate la.
A bandeira limita quanto tempo uma pre-autorizacao pode esperar, e o agendamento
respeita isso: se delayHours passar do prazo, a captura e marcada para 1 hora
antes do vencimento (authorizationExpiresAt), nunca depois. Veja os prazos e
o aviso de vencimento em
Transacoes.
Pausas: Aguardar e Revisao manual
Essas etapas nunca seguram a autorizacao. A execucao pausa, o pagamento
fica requires_action e a resposta da API volta na hora. Depois:
- Aguardar retoma sozinho pela porta
nextquando o prazo vence; - Revisao manual retoma pela decisao de um analista ou, se ninguem decidir
no prazo (
slaHours), pela decisao automaticaonSlaBreach.
A decisao e uma chamada idempotente:
curl -X POST http://localhost:3333/v1/payments/pay_.../review \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Idempotency-Key: revisao-pay_..." \
-H "Content-Type: application/json" \
-d '{ "decision": "approve", "note": "Cliente confirmou por telefone." }'
O fluxo continua de onde parou - aprovar pode disparar a autorizacao no
adquirente - e a resposta traz o pagamento ja com o status final. Se a revisao
ja foi decidida (por outra pessoa ou pelo prazo), a API responde 409.
Notificar o seu sistema
O no Notificar webhook emite o evento flow.notification ao fim da
execucao, com o nome escolhido no no em data.name. Assine esse evento uma vez
e use o nome para saber em que ponto do fluxo o pagamento passou:
{
"type": "flow.notification",
"data": {
"name": "antifraude_em_revisao",
"paymentId": "pay_...",
"flowId": "flw_...",
"flowRunId": "frun_..."
}
}
Campos disponiveis nas regras
As condicoes comparam campos de um catalogo fechado:
| Campo | Exemplo de uso |
|---|---|
payment.amount | Valor em centavos. > 10000 e acima de R$ 100,00 |
payment.installments | Numero de parcelas |
payment.initiator | customer (cliente presente) ou merchant (automatica) |
card.brand | visa, mastercard, elo, amex, hiper |
card.bin | Primeiros digitos, para regra por emissor |
card.funding | credit, debit, prepaid |
card.country | Pais emissor, para regra de cartao estrangeiro |
card.verification_status | Resultado da validacao de cartao: valid, invalid ou unavailable. Vazio se o cartao nunca foi validado |
card.verified_days_ago | Dias desde a ultima validacao do cartao. Vazio se nunca foi validado; > 30 pega validacao antiga |
customer.tags | Etiquetas do cliente |
customer.groups | Grupos do cliente (ids cgr_...); o editor mostra os nomes |
customer.is_first_purchase | Primeira compra |
risk.score | Score do antifraude (0 a 100) |
attempt.number | Numero da tentativa |
attempt.previous_decline_reason | Motivo da recusa anterior |
subscription.is_recurring | E cobranca de assinatura |
metadata.<chave> | Qualquer metadado que voce enviou |
O catalogo e fechado de proposito. Expressao livre tornaria o fluxo impossivel de validar antes de publicar - e um fluxo invalido em producao decide o roteamento de dinheiro real.
Nao existe operador de expressao regular, tambem por decisao: regex fornecida
pelo usuario, avaliada no caminho critico de autorizacao, e vetor de ataque de
negacao de servico. contains, starts_with e ends_with cobrem os casos
reais.
Estrategias de roteamento
O no Rotear aceita varios conectores candidatos e quatro estrategias:
| Estrategia | Comportamento | Quando usar |
|---|---|---|
priority | Tenta na ordem definida | Tem um adquirente preferido |
weighted | Sorteia pelo peso (%) | Teste A/B ou divisao de volume (80/20) |
least_cost | Usa o custo cadastrado | Otimizar taxa |
round_robin | Alterna igualmente | Distribuir carga |
Cartao: uma adquirente por transacao
O token de um cartao e emitido por UMA adquirente - o CardToken da Cielo, o
tokenizationId da Rede - e so vale nela. Por isso, no cartao:
- o cartao salvo vai sempre para a conta onde foi salvo (
connectorAccountIdinformado no cadastro do cartao), mesmo que a estrategia do no aponte outra. Se o no de rota nao tiver essa conta, o pagamento falha comno_connector_availablee a mensagem diz qual conta incluir; - recusa ou falha nao trocam de adquirente. A nova tentativa e da politica
de retentativa (Retentativa), que respeita a ABECS e o
intervalo pedido pelo emissor, na mesma adquirente. O detalhe da transacao
mostra o motivo
card_single_acquirer.
A excecao e o token de bandeira proprio (card.isNetworkToken: true) quando
todas as contas do no aceitam token de bandeira externo: ai o fallback abaixo
vale tambem para o cartao.
Fallback
Vale para Pix e boleto, que nao dependem de token, e para cartao com token de bandeira proprio. Duas opcoes por no de roteamento:
fallbackOnConnectorFailure- tenta o proximo em timeout ou erro do provedor. Recomendado deixar ligado: a chance de pagamento segue intacta.fallbackOnReversibleDecline- tenta o proximo em recusa reversivel (so cartao com token de bandeira proprio).
Recusa irreversivel sempre interrompe o fallback, independentemente da configuracao. O emissor nunca aprovaria, portanto tentar outro adquirente seria custo garantido sem chance de aprovacao. Ver Retentativa.
Simule antes de publicar
No editor, o botao Simular percorre o grafo com um contexto hipotetico e mostra o caminho que a transacao seguiria, com a explicacao de cada decisao. Nenhum conector e acionado e nada e gravado.
Por API:
curl -X POST http://localhost:3333/v1/flows/simulate \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"graph": { "nodes": [], "edges": [] },
"context": {
"payment.amount": 1500000,
"card.brand": "visa",
"risk.score": 20
}
}'
Resposta:
{
"outcome": "aprovado",
"path": [
{ "nodeId": "trigger", "explanation": "Gatilho: payment.authorization_requested." },
{
"nodeId": "faixas",
"handle": "alto",
"explanation": "Caso \"Acima de R$ 10.000,00\": payment.amount (1500000) maior que 1000000 => sim"
},
{
"nodeId": "antifraude",
"handle": "approve",
"explanation": "Score simulado 20 resultaria em approve."
},
{
"nodeId": "rota-alto",
"handle": "approved",
"explanation": "Rotearia para ca_adquirente_y (estrategia priority)."
}
]
}
Etapas que dependem de terceiros seguem o caminho feliz por padrao. Para ver o
outro caminho, informe o resultado suposto em assume, por tipo de no ou por
id: "assume": { "route": "declined" } responde "e se o adquirente recusar?".
Regras (condicao, multiplos caminhos) nunca sao supostas: sao elas que se quer
testar.
Versionamento
Publicar cria uma versao imutavel e move o ponteiro da versao ativa.
Isso permite duas coisas que importam em operacao:
- auditar por que uma transacao de tres meses atras foi roteada de certo jeito - o grafo exato daquele momento esta preservado;
- voltar atras instantaneamente, trocando o ponteiro para a versao anterior.
Cada execucao grava a trilha passo a passo em flow_run_steps, com a
explicacao de cada decisao em portugues. Quando o cliente pergunta por que a
transacao foi para o adquirente X, a resposta esta no banco.
Validacao na publicacao
Antes de uma versao entrar em vigor, verificamos:
- Schema - estrutura de cada no e de cada regra;
- Grafo - exatamente um gatilho, nenhum ciclo, nenhuma porta sem ligacao, nenhum no terminal com saida, ao menos um no de Aprovar ou Recusar;
- Referencias - toda conta de conector e todo recebedor citados existem, pertencem a sua organizacao, estao no mesmo ambiente e estao habilitados.
A terceira camada evita o erro mais silencioso: publicar um fluxo que aponta para uma conta desabilitada recusaria transacoes reais sem nenhuma pista.
Rascunhos aceitam configuracao incompleta - salvar nunca perde o trabalho em
andamento. A resposta do rascunho e de POST /v1/flows/validate lista cada
problema com o no (nodeId) e o campo (field), e o painel marca os dois.
Um fluxo em vigor por gatilho
Cada gatilho tem um fluxo em vigor por ambiente. Publicar coloca o fluxo em
vigor para o gatilho desenhado nele e tira o anterior - a resposta informa
quais sairam em replacedFlows. Para voltar ao fluxo antigo, publique-o de
novo.
A cobranca de fatura da recorrencia usa o fluxo do gatilho
invoice.payment_due; sem ele publicado, usa o de
payment.authorization_requested. Quem so desenhou o roteamento cobra a
recorrencia pelo mesmo caminho; quem quer tratar fatura de outro jeito (outro
adquirente, outra regra) publica um fluxo proprio para ela. Nos dois casos o
contexto traz subscription.is_recurring verdadeiro.