Skip to content

Payment Config ​

Visão Geral ​

Múltiplos gateways de pagamento (Stripe, Stone, Rede, MercadoPago, MFE/SAT) coexistem e podem ser selecionados por canal e filial. O PaymentConfigService é o roteador que decide qual gateway atende cada transação.

Princípio de cascata: se gateway primário falha (timeout, taxa de erro alta), o sistema automaticamente tenta o próximo configurado. Operação não para por outage de um único provider.

Localização ​

CamadaArquivo
Modulebackend/src/payment-config/payment-config.module.ts
Servicebackend/src/payment-config/payment-config.service.ts
Schemabackend/src/payment-config/schemas/payment-config.schema.ts
Health monitorbackend/src/payment-config/gateway-health.service.ts
Viewfrontend-react/src/views/admin/PaymentConfigView.tsx

Rota ​

/t/:slug/admin/payment-config (sub-aba dentro de Configurações)


PaymentConfig Schema ​

CampoTipoDescrição
tenantObjectIdTenant
branchObjectId?null = configuração default do tenant; setado = override por filial
channelenumpdv | balcao | kiosk | delivery | online_checkout
paymentMethodenumcredit | debit | pix | voucher | cash
cascadeobject[]Ordem de gateways a tentar (com fallback)
activeboolean

Cada item da cascade:

CampoTipo
providerenum: stripe | stone | rede | mercadopago | sitef | rede_tef
prioritynumber (1 = primeiro a tentar)
credentialsRefstring (ref para integration record)
enabledboolean
maxRetriesnumber
timeoutMsnumber

Flow de Roteamento ​

PaymentConfigService.resolveGateway(tenantId, branchId, channel, method):

  1. Lookup PaymentConfig com (tenant, branch, channel, method). Se não existir, fallback (tenant, null, channel, method) — config default.
  2. Lê cascade ordenada por priority
  3. Para cada gateway, verifica:
    • enabled: true
    • gatewayHealth.isHealthy(provider, last5min) — circuit breaker integrado
  4. Retorna o primeiro healthy. Se nenhum, retorna o primeiro do cascade (best-effort).

Result:

ts
{
  provider: 'stripe',
  credentials: { ... },
  fallbackChain: ['stone', 'rede'],  // próximas tentativas se stripe falhar
}

PaymentService consome esse resultado e tenta a transação. Em failure, automaticamente tenta fallbackChain[0], e assim por diante.


Circuit Breaker ​

GatewayHealthService mantém em Redis sliding-window 5min:

  • gateway:{provider}:errors_5min — counter de falhas
  • gateway:{provider}:total_5min — counter total

isHealthy(provider) retorna false quando errors_5min / total_5min > 0.3 (>30% error rate).

Gateway entra em half-open após 60s — permite 1 transação de teste; sucesso fecha o circuit, falha mantém aberto.

Visualização: Sistema → Pagamentos → Health mostra status por gateway com sparkline de error rate.


Endpoints ​

MétodoRotaPermissão
GET/admin/payment-configsettings.manage.integrations
PUT/admin/payment-configsettings.manage.integrations
GET/admin/payment-config/healthaudit_log.view
POST/admin/payment-config/test/:providersettings.manage.integrations

POST .../test/:provider faz uma transação de R$ 0,01 com auto-reverso para validar credenciais sem custo real.


Configurações Comuns ​

Default do tenant (sem branch override) ​

json
{
  "channel": "pdv",
  "paymentMethod": "credit",
  "cascade": [
    { "provider": "stone", "priority": 1, "enabled": true },
    { "provider": "rede", "priority": 2, "enabled": true },
    { "provider": "stripe", "priority": 3, "enabled": false }
  ]
}

PDV cartão crédito: tenta Stone primeiro (terminal físico TEF), Rede como backup, Stripe nunca (não usado em PDV físico).

Filial específica com gateway próprio ​

Filial centro tem contrato com Cielo (gateway proprietário não suportado nativamente). Override:

json
{
  "branch": "<centro>",
  "channel": "pdv",
  "paymentMethod": "credit",
  "cascade": [
    { "provider": "rede", "priority": 1, "enabled": true }
  ]
}

Resto das filiais segue o default do tenant.

Online checkout com Pix Stripe ​

json
{
  "channel": "online_checkout",
  "paymentMethod": "pix",
  "cascade": [
    { "provider": "mercadopago", "priority": 1 },
    { "provider": "stripe", "priority": 2 }
  ]
}

MP é primeira escolha para PIX brasileiro (UX melhor); Stripe BR como backup.


Race Conditions ​

Gateway resolution + transaction submission não é atômico. Cenário:

  1. T0: resolveGateway returns stripe
  2. T1: stripe entra em outage (3s depois)
  3. T2: transação é submetida → falha
  4. PaymentService captura erro, marca circuit, tenta fallbackChain[0] (stone)

Tempo total adicional: ~3s timeout + 100ms retry. Aceitável para fluxo síncrono de PDV.

Para PDV TEF (Sitef/Rede via terminal físico), cascade não funciona — operador escolhe manualmente o terminal usado. Cascade é apenas para gateways de internet.


Audit ​

Cada mudança em PaymentConfig é audit-logged:

  • payment_config.cascade.updated
  • payment_config.gateway.disabled
  • payment_config.test.executed

Mudança de cascade é alta criticidade — se admin desabilita um gateway acidentalmente, pode parar pagamentos. Audit + alerta verbal no UI ("Confirmar — esta ação afeta pagamentos imediatamente").


Limitações ​

  • Cascade não considera latência — só health (binary). Gateway lento mas online é tratado como healthy. Roadmap: latency-aware routing.
  • Fees/taxas não influenciam roteamento — se Stone cobra 1.99% e Rede 2.5%, sistema prefere o de menor priority (admin escolheu manualmente). Otimização por custo é manual.
  • Crypto/USDT/etc. — não suportado. Se aparecer demanda, abrir feature request.

Roadmap ​

  • Roteamento por menor custo total (taxa + tempo) — feature flag-gated
  • Health beyond circuit breaker — incluir P95 latency + auth-failure-rate
  • Per-customer routing — VIP cliente recebe gateway de menor latência mesmo que mais caro

Lançado sob a licença MIT.