Primeiro depósito e primeiro saque no sandbox da Nero¶
Para: Dev — Conferido em 2026-10-18.
Roteiro para a Nero ver o ciclo inteiro funcionando na operação nero-br-hml (operação Teste) antes de escrever o conector. Nenhum dinheiro real se move. Os comandos genéricos estão em Primeiro depósito e primeiro saque; esta página traz as constantes e os resultados esperados da Nero.
O que é¶
Os dez passos usam o cliente de shell de Exemplos executáveis (bash, openssl, curl) e python3 ou jq só para ler JSON. O shell serve para depurar: em produção use Go ou Node, com comparação em tempo constante e segredo fora da linha de comando.
Quando usar¶
No primeiro dia de integração, antes de abrir qualquer rota do portal. Cada passo mostra o que o conector da Nero deve fazer com o resultado.
Como funciona¶
Passo 0: pré-requisitos¶
- Credenciais da operação Teste: chave
key_test_com os escoposdeposits:write,withdrawals:writeeread, o segredo num arquivo0400e o segredo de webhook. - URL de webhook cadastrada na operação. Fora de produção, o Dracma só entrega a domínios reservados ou liberados no onboarding: peça a liberação do domínio de hml da Nero. Sem a URL, os passos de webhook mostram só o log de entregas.
- Relógio sincronizado (NTP): a janela é de ±300 segundos.
- As variáveis do cliente (
DRACMA_BASE_URL,DRACMA_KEY_ID,DRACMA_KEY_SECRET_FILE) e as funçõesdr,jsenovo_iddo roteiro genérico.
Passo 1: ping¶
dr GET /ping
Esperado: 200 com operation_id, environment: "sandbox" e server_time. Compare server_time com date -u: desvio acima de 5 segundos pede NTP. 401 unknown_key é chave de outro tipo ou revogada; 401 invalid_signature é segredo ou path errado; 401 timestamp_out_of_window é relógio.
Passo 2: moedas, métodos e exigências¶
dr GET /currencies
Esperado: BRL com methods: ["pix"]. Se deposit_requirements for ["player.name", "player.email"], o PSP de depósito da operação é o Mercado Pago: os dois campos são obrigatórios e o e-mail tem de ser .test, .invalid ou .example. Com ["player.name"], é a MaximaxPay; com [], o simulador.
Passo 3: primeiro depósito¶
DEP_EXT="dep_$(novo_id)"
cat > nero-dep.json <<EOF
{"external_id":"$DEP_EXT","player":{"external_ref":"nero-hml-jogador-0001","document":{"type":"CPF","number":"52998224725","country":"BR"},"name":"Jogador Teste","email":"jogador1@nero.test","ip":"203.0.113.10"},"amount":{"amount":"5000","currency":"BRL"},"method":"pix"}
EOF
dr POST /deposits nero-dep.json "$DEP_EXT" | tee nero-dep-resp.json
DEP_ID=$(js '["id"]' < nero-dep-resp.json)
52998224725 é um CPF de teste (Dados de teste). Esperado: 201 com pending e instructions.pix.copy_paste contendo SANDBOX, ou 202 com created (espere uns segundos e faça o passo 5). Repetindo exatamente o mesmo comando (mesmo arquivo, mesma chave) a resposta é a mesma, com Idempotent-Replayed: true.
Passo 4: pagar no sandbox¶
dr POST "/sandbox/deposits/$DEP_ID/pay" "" "sbx_$(novo_id)"
Corpo vazio é "pago pelo próprio jogador, valor exato". Para os caminhos de revisão, mande outro payer_document e veja under_review com PAYER_MISMATCH (Receitas por caminho).
Passo 5: fetch-back¶
dr GET "/deposits/$DEP_ID" | js '["status"], v["version"], v["amount"]'
Esperado: paid, versão 3 e 5000 BRL. É aqui, e só aqui, que o conector credita, depois de conferir external_id, amount, currency e player_ref com o que gravou.
Passo 6: eventos e webhook¶
dr GET "/events?object_id=$DEP_ID" # deposit.pending e deposit.paid, na ordem
dr GET /sandbox/webhooks # log de entregas: evento, tentativa e o status HTTP da Nero
EVT=$(dr GET "/events?object_id=$DEP_ID" | js '["data"][-1]["id"]')
echo "{\"event_id\":\"$EVT\"}" > redeliver.json
dr POST /sandbox/webhooks/redeliver redeliver.json "sbx_$(novo_id)"
Esperado no receptor da Nero: o mesmo Dracma-Event-Id, resposta 200 e nenhum crédito novo.
Passo 7: primeiro saque¶
A reserva no nero_ledger acontece antes deste POST. O primeiro saque de um jogador costuma ir para revisão.
WDR_EXT="wdr_$(novo_id)"
cat > nero-wdr.json <<EOF
{"external_id":"$WDR_EXT","player":{"external_ref":"nero-hml-jogador-0001","document":{"type":"CPF","number":"52998224725","country":"BR"},"name":"Jogador Teste","ip":"203.0.113.10"},"amount":{"amount":"2000","currency":"BRL"},"method":"pix","destination":{"pix":{"key_type":"cpf","key":"52998224725"}},"review_requested":false}
EOF
dr POST /withdrawals nero-wdr.json "$WDR_EXT" | tee nero-wdr-resp.json
WDR_ID=$(js '["id"]' < nero-wdr-resp.json)
dr POST "/sandbox/withdrawals/$WDR_ID/approve" "" "sbx_$(novo_id)" # simula o revisor no painel
Esperado: 201 com under_review, decision.mode: manual e FIRST_WITHDRAWAL em decision.reasons; depois do approve, approved. O simulador paga sozinho em seguida; confira com dr GET "/withdrawals/$WDR_ID" até paid e psp_reference. No conector: finalizar a reserva só ao ler paid no fetch-back.
Passo 8: segundo saque, o caminho automático¶
Com o primeiro saque pago e X = 1 (D2), um saque que caiba em "depositado menos sacado" (aqui, até R$ 30,00) tende a sair no automático:
WDR2_EXT="wdr_$(novo_id)"
sed "s/$WDR_EXT/$WDR2_EXT/" nero-wdr.json > nero-wdr2.json
dr POST /withdrawals nero-wdr2.json "$WDR2_EXT" | js '["status"], v["decision"]["mode"], v["decision"]["reasons"]'
Esperado: approved, automatic e lista vazia. Se vier under_review, leia decision.reasons: as regras da operação (GET /v1/rules) podem pedir revisão por outros motivos. Sem player.ip o resultado é sempre under_review com OWNERSHIP_UNVERIFIED. Para ver a devolução da reserva, crie outro saque de valor terminado em 77 e chame .../fail ou .../reject.
Passo 9: queda simulada e retomada sem duplicar¶
echo '{"down":true}' > down.json; echo '{"down":false}' > up.json
dr POST /sandbox/outage down.json "sbx_$(novo_id)"
DEP2_EXT="dep_$(novo_id)"; sed "s/$DEP_EXT/$DEP2_EXT/" nero-dep.json > nero-dep2.json
dr POST /deposits nero-dep2.json "$DEP2_EXT" # 503 service_unavailable, Retry-After 5
dr POST /sandbox/outage up.json "sbx_$(novo_id)"
dr POST /deposits nero-dep2.json "$DEP2_EXT" # MESMA chave e corpo: 201 ou 202
dr POST /deposits nero-dep2.json "$DEP2_EXT" # mesma resposta, Idempotent-Replayed: true
dr GET "/deposits?external_id=$DEP2_EXT" | js '["data"].__len__()' # 1
É exatamente o comportamento que o outbox do nero_payments precisa ter em produção.
Passo 10: no dia seguinte, a reconciliação¶
ONTEM=$(date -u -d yesterday +%F)
dr GET "/reconciliation?date=$ONTEM¤cy=BRL&limit=200"
Esperado depois das 02:00 UTC: itens deposit e withdrawal com status: paid, totals, digest e o header Dracma-Signature na última página. Antes disso: 409 day_open com Retry-After. Confira o digest com Digest e VerifyDigest dos exemplos.
Exemplos¶
Todo o roteiro é o exemplo. Os resultados esperados de cada passo estão logo abaixo do comando.
Erros e casos de borda¶
| Se vier | Causa provável |
|---|---|
400 com required_by_operation ou reserved_domain_required no depósito |
Falta player.name ou player.email, ou o e-mail não é de domínio reservado (passo 2) |
422 insufficient_operation_balance no saque |
A operação ainda não tem caixa livre: pague o depósito do passo 4 antes |
409 invalid_state_transition no pay do saque |
O simulador já pagou sozinho; use valor terminado em 77 para controlar |
429 rate_limited |
Limite de depósitos ou saques por jogador por hora; use outro external_ref |