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. 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.