Fluxo ponta a ponta

Para: Dev — Conferido em 2026-10-18.

Quem fala com quem, em que ordem, e onde cada garantia (idempotência, fetch-back, reserva) acontece no conector da Nero. Os detalhes de implementação estão em Depósito, Saque e Webhook, eventos e reconciliação.

O que é

O desenho geral está em Arquitetura do conector. Aqui ficam os nomes dos componentes da Nero e as fronteiras entre eles.

flowchart LR J["Jogador: navegador ou app"] -->|"sessão da bet, cookie HttpOnly"| F["nero_client (front)"] F -->|"HTTPS, sem segredo no bundle"| P["nero_portal"] P -->|"X-Nero-Identity (asserção assinada)"| C["nero_payments (conector e outbox dracma_intents)"] C <-->|"reserva, crédito, devolução"| L["nero_ledger (carteira)"] C -->|"HMAC e Idempotency-Key"| D["Dracma API /v1"] D -->|"credencial de PSP, nunca sai do Dracma"| PSP["PSP PIX"] PSP -->|"callback, termina no Dracma"| D D -->|"webhook assinado"| CD["Caddy da bet"] CD -->|"POST /api/payments/dracma/webhook"| C C -->|"fetch-back em /v1/deposits/id e /v1/withdrawals/id"| D
Fronteira O que cruza O que nunca cruza
Jogador para o portal Sessão, valor, método, chave PIX de saque, CPF Nada do Dracma
Portal para o nero_payments X-Nero-Identity (quem é o jogador) e o corpo do pedido Identidade vinda do corpo
nero_payments para o Dracma external_id, player.external_ref (opaco), documento, nome, e-mail, IP e device (risco e exigências), valor na menor unidade, destino do saque, review_requested Senha, sessão, token da bet, dados de jogo
Dracma para o nero_payments Objetos de depósito e saque, BR Code, eventos assinados, reconciliação Credencial de PSP, dados de outra operação

Quando usar

Use esta página para ver o conjunto antes de implementar uma rota. Os dois diagramas abaixo mostram o caminho feliz; os casos de borda estão em cada página de implementação.

Como funciona

Depósito

sequenceDiagram autonumber participant J as Jogador (front) participant P as nero_portal participant C as nero_payments participant O as outbox dracma_intents participant D as Dracma participant S as PSP PIX J->>P: POST /api/payments/deposits {amount: 50.00, method: pix} P->>C: repassa com X-Nero-Identity C->>O: grava intent (external_id dep_uuidv7, valor em centavos, player_ref) na MESMA transação C->>D: POST /v1/deposits (Idempotency-Key = external_id, timeout 10 s) D->>S: cria a cobrança PIX D-->>C: 201 pending com instructions.pix (ou 202 created) C-->>J: 201 {deposit_id, status: pending, pix.copy_paste, expires_at} J->>S: paga o PIX no app do banco S-->>D: confirmação do pagamento D->>D: confere valor e pagador e vai a paid D->>C: webhook deposit.paid (assinado) C->>C: verifica assinatura e janela, dedup por Dracma-Event-Id C->>D: GET /v1/deposits/dep_... (fetch-back) D-->>C: status paid, amount, external_id, player_ref C->>C: confere com o intent e credita UMA vez (idempotente por external_id) C-->>D: 200 J->>P: GET /api/payments/deposits/dep_... (polling) P->>C: repassa C-->>J: status paid
  • Se o POST /v1/deposits der timeout, 5xx ou 429, o intent continua no outbox e um worker repete com a mesma chave. O front recebe 202 {status: creating} e faz polling.
  • Se o webhook se perder, o job de GET /v1/events (a cada 5 minutos) encontra o deposit.paid e passa pelo mesmo caminho: dedup, fetch-back e crédito.
  • O polling do front lê o estado local do nero_payments. Não é um proxy para o Dracma.

Saque

sequenceDiagram autonumber participant J as Jogador (front) participant P as nero_portal participant C as nero_payments participant L as nero_ledger participant D as Dracma participant S as PSP PIX J->>P: POST /api/wallet/withdraw/request {amount, type: pix, pix_key, pix_type} P->>C: repassa com X-Nero-Identity e o IP do jogador C->>L: RESERVA o valor (débito) na mesma transação do intent wdr_uuidv7 C->>D: POST /v1/withdrawals (Idempotency-Key = external_id, player.ip) D->>D: motor de regras: automático, revisão ou bloqueio alt bloqueio (422) D-->>C: 422 com o code C->>L: devolve a reserva C-->>J: 200 {status: false, message} (mensagem genérica) else automático ou revisão D-->>C: 201 approved ou under_review C-->>J: 200 {status: true, withdrawal_id, state: processing ou under_review} end D->>S: envia o PIX (automático, ou depois da aprovação no painel) S-->>D: liquidado (E2E id) D->>C: webhook withdrawal.paid C->>D: GET /v1/withdrawals/wdr_... (fetch-back) D-->>C: status paid, psp_reference C->>L: finaliza a reserva (saída definitiva) C-->>D: 200
  • A reserva vem antes do POST e só volta em rejected, failed ou cancelled (confirmados por fetch-back) ou em 4xx conclusivo. Timeout e 5xx não devolvem reserva.
  • under_review é decidido por revisores da Nero no painel do Dracma. O resultado chega por webhook como approved, processing, paid, ou rejected.

O outbox dracma_intents

O modelo geral (colunas, estados e regras) está em Arquitetura do conector. Na Nero:

  • A tabela se chama dracma_intents. O external_id é dep_<uuidv7> ou wdr_<uuidv7> e é também o deposit_id e o withdrawal_id que o front enxerga.
  • Backoff de 1 s, 2 s, 4 s e assim por diante, até 60 s, respeitando o Retry-After.
  • A métrica nero_dracma_outbox_pending e o alerta de intent pendente há mais de 10 minutos estão em Webhook, eventos e reconciliação.

Exemplos

O passo a passo em comandos, contra a operação nero-br-hml, está em Primeiros passos no sandbox.

Erros e casos de borda

O que o Dracma garante e o que é da Nero

Garantia Quem
Não criar duas cobranças nem dois saques para a mesma chave Dracma, desde que a Nero repita com a mesma chave
Não pagar para chave PIX de terceiro; decidir automático, revisão ou bloqueio Dracma (motor de regras e consulta de titularidade)
Creditar uma vez, só em paid Nero (fetch-back e idempotência por external_id)
Reservar antes, devolver só em estado conclusivo Nero
Não perder evento Os dois: o Dracma reentrega por 72 horas e mantém GET /events; a Nero roda o job de 5 minutos
Provar que os dois livros batem Os dois: reconciliação diária com digest assinado

Veja também