Dracma — guia de integração para operadores

O Dracma é um gateway de pagamento multi-tenant. Seu serviço (o conector) chama a API do Dracma para cobrar depósitos e pagar saques dos seus jogadores; o Dracma fala com os bancos e PSPs, aplica o motor de regras (saque automático x revisão manual) e avisa o resultado por webhook assinado.

Este guia foi feito para que qualquer serviço consiga se integrar sozinho: ler, implementar, rodar a suíte de conformidade no sandbox e cumprir o checklist de produção, sem precisar de reunião com o time do Dracma.

Base normativa. Este guia segue o Contrato de integração v1, versão 1.1.0 e o openapi.yaml que a API serve (o diff contra o contrato está em referencia/openapi.md). O YAML dá a forma (campos, tipos); o contrato dá a semântica (assinatura, idempotência, máquinas de estado, fetch-back). Se este guia e o contrato divergirem, vale o contrato, e a divergência é bug deste guia. Mudança incompatível só acontece como /v2; a v1 só recebe acréscimos (campos, estados, eventos e códigos novos). Por isso seu código deve ser um leitor tolerante (veja webhooks.md e erros-e-idempotencia.md).

1. O que está disponível agora

Estado conferido no código do dracma_api (rotas em internal/interface/http/v1/) em 2026-09-27.

Item Estado
Método pix em BRL (depósito e saque) implementado
Transporte, assinatura HMAC, allowlist de IP, escopos, idempotência, rate limit, formato de erro, GET /v1/ping implementado
POST/GET /deposits, GET /deposits/{id}, POST /deposits/{id}/cancel implementado (depositos.md)
POST/GET /withdrawals, GET /withdrawals/{id}, POST /withdrawals/{id}/cancel implementado (saques.md)
GET /events, GET /reconciliation, GET /balances, GET /currencies, GET /rules, GET /players/{ref}/limits, POST /rules/change-requests implementado
Rotas /sandbox/* (pay, expire, refund, chargeback, ações de saque, outage, webhooks, redeliver) implementado (só em sandbox; em produção 404)
Entrega de webhooks assinados (serviço dracma_webhooks) implementado
Exigências de depósito por operação (deposit_requirements/psp_notes em GET /currencies; ex.: player.name + player.email obrigatórios quando o PSP de depósito é o Mercado Pago) implementado (dracma_api 6d81813) — ver a seção "Exigências por operação" de depositos.md
POST /fx/quotes responde 422 fx_not_enabled (câmbio desligado em toda operação)
GET /fx/quotes/{id}, GET /receipts, GET /receipts/{id}, POST /withdrawals/{id}/recall, POST /sandbox/bank-transfers/incoming rotas do contrato 1.1.0 no recorte PIX: 404, página vazia, 404, 409 invalid_state_transition, 400 rail_not_enabled (referencia/openapi.md)
card, crypto, boleto, bank_transfer, wire, swift não disponível — 400 method_not_enabled
Verificação do certificado mTLS de cliente na borda (proxy TLS) de produção, fora do código da API — ver divergencias.md
Estorno/chargeback de depósito e devolução (returned) de saque em produção sem gatilho ainda (no sandbox existem as ações refund, chargeback e return) — ver divergencias.md

Onde o código e o contrato divergem, cada página diz o que o código faz hoje e a divergência está listada em divergencias.md. Confira no sandbox antes de ir para produção.

2. Vocabulário mínimo

Termo Significado
Tenant A empresa cliente do Dracma (pessoa jurídica).
Operação Um deployment/marca de um tenant, por país e ambiente (ex.: minhabet-br-hml, minhabet-br-prd). É a unidade de credencial, regra, moeda, webhook e saldo. Tudo o que você faz está preso a uma operação.
Conector O seu serviço que fala com o Dracma. Só ele guarda as credenciais.
Jogador Seu usuário final. No Dracma é identificado por player.external_ref: opaco, imutável, nunca e-mail nem telefone.
external_id O id que você dá a cada depósito/saque. Único por operação e por tipo. É a sua âncora de idempotência e de conciliação.
Fetch-back Consultar GET /deposits/{id} ou GET /withdrawals/{id} antes de mover dinheiro. O corpo do webhook nunca é a fonte de verdade.

Tenant e operação vêm só da sua credencial (chave de API + certificado mTLS). Qualquer operation_id que você mandar no corpo é ignorado — e, nos corpos de criação, recusado como campo desconhecido.

3. Ambientes

Ambiente Base URL Prefixo da chave Dinheiro real? mTLS
sandbox https://sandbox.dracma.example/v1 key_test_ Nunca. PIX sintético (recebedor sandbox@dracma.invalid, marcador SANDBOX no BR Code) recomendado
production https://api.dracma.example/v1 key_live_ Sim obrigatório
  • Cada ambiente recusa a chave do outro com 401 unknown_key (isso já está implementado). É a trava que evita apontar homologação para produção por engano.
  • As rotas /sandbox/* só existem no sandbox; em produção respondem 404.
  • O GET /v1/ping diz em qual ambiente e operação a sua chave caiu — use-o como primeiro teste:
{ "ok": true, "operation_id": "…", "environment": "sandbox", "server_time": "2026-09-27T12:00:00Z" }

Os hosts *.dracma.example deste guia são ilustrativos; os hosts reais chegam junto com as credenciais no onboarding.

4. Como pedir credenciais (onboarding)

O onboarding é feito pelo time do Dracma, uma vez por tenant, e depois por operação. Do seu lado:

  1. KYB do tenant — razão social, documento fiscal, sócios e licença para operar no país. Aprovado por duas pessoas do Dracma.
  2. Defina as operações — uma por marca × país × ambiente (<marca>-<país>-<hml|prd>), com fuso, idioma padrão, moedas e métodos.
  3. Acesso ao painel — o admin do seu tenant recebe convite e convida financeiro, revisores e auditor. O painel usa login com 2 fatores; não há trava de IP para pessoas.
  4. Regras — o conjunto de regras inicial (limites, multiplicador X× do saque automático, horários) é publicado pelo painel com aprovação de duas pessoas. A API só lê regras e propõe mudanças.
  5. Credenciais de sandbox — você recebe: key_test_… + segredo (exibido uma única vez), segredo de webhook whsec_… (diferente do segredo de chamada), e cadastra no painel a allowlist de IP de saída do seu conector (lista de IPs/CIDRs, IPv4 e IPv6) e a URL de webhook.
  6. Conformidade — rode a suíte de conformidade contra a sua operação de sandbox (sandbox.md). Verde é pré-requisito de produção.
  7. Reconciliação de um dia de sandbox comparada nos dois lados (reconciliacao.md).
  8. Produção — certificado mTLS de cliente emitido pela CA do Dracma, key_live_…, allowlist de produção, limites conservadores, primeira transação real de valor mínimo acompanhada, caixa inicial conferido em GET /balances.
  9. Registro de go-live com responsáveis dos dois lados — o checklist está em go-live-operador.md.

Criar chave nova exige aprovação dupla no painel; revogar exige uma pessoa. Guarde segredos no seu cofre, nunca em repositório, imagem de container ou variável NEXT_PUBLIC_*/VITE_*: o Dracma é chamado só do servidor, nunca do navegador ou do app do jogador.

5. Mapa da documentação

Documento Para quê
autenticacao.md Assinar chamadas (HMAC, nonce, janela de 300 s), mTLS, allowlist de IP, escopos, rotação de chaves. Com exemplo trabalhado byte a byte.
webhooks.md Verificar webhooks, deduplicar, fetch-back obrigatório, retries, ordem, leitor tolerante, recuperação por GET /events.
depositos.md Máquina de estados do depósito, endpoints, o que credita o jogador.
saques.md Reserva antes do saque, máquina de estados, decisão automática x revisão, decision.reasons.
erros-e-idempotencia.md Catálogo de erros, regra de ouro de repetição, Idempotency-Key, external_id.
reconciliacao.md Relatório diário assinado, digest, job de 5 min de /events.
sandbox.md Rotas /sandbox/* para exercitar cada caminho; suíte de conformidade.
go-live-operador.md Checklist que você cumpre antes de produção.
exemplos/ Clientes mínimos em Go, Node (TypeScript), PHP e shell que assinam chamadas e verificam webhooks, com testes que reproduzem os vetores normativos.
referencia/openapi.yaml O documento OpenAPI 3.1 que a API serve (GET /openapi.yaml).
referencia/openapi.md O que o documento servido muda em relação ao contrato 1.1.0 e por quê.
divergencias.md Divergências conhecidas entre o código atual e o contrato, e o que fazer com cada uma.
nero/ Guia específico para o time da Nero implementar o conector nero_payments.

6. Convenções que valem em toda a API

  • Dinheiro é sempre Money: {"amount": "5000", "currency": "BRL"}. amount é string de inteiro na menor unidade (R$ 50,00 = "5000"). Nunca float, nunca vírgula.
  • Tempo é RFC 3339 em UTC (2026-09-26T15:04:05Z).
  • IDs do Dracma são opacos com prefixo (dep_, wdr_, evt_, rcn_, chg_). Não derive nada do formato.
  • Erro é application/problem+json (RFC 9457) com code estável, retryable e trace_id.
  • Toda resposta traz Dracma-Trace-Id; você pode mandar um W3C traceparent e ele é adotado. Registre o trace id nos seus logs: é o que o suporte pede.
  • Corpo application/json; charset=utf-8, máximo 64 KiB.
  • Timeout do cliente: 10 s. O Dracma responde POST /deposits e POST /withdrawals em até 8 s; se o PSP demorar, responde 202 e segue por webhook.
  • Leitor tolerante: campo desconhecido é ignorado; status, tipo de evento, method ou code desconhecido nunca move dinheiro — é tratado como não-terminal e conferido depois.

7. Em uma página: o fluxo feliz

sequenceDiagram
  participant J as Jogador
  participant C as Seu conector
  participant D as Dracma
  J->>C: quero depositar R$ 50
  C->>D: POST /v1/deposits (assinado, Idempotency-Key)
  D-->>C: 201 {id: dep_…, status: pending, instructions.pix.copy_paste}
  C-->>J: mostra QR / copia-e-cola
  J->>D: paga o PIX (no banco dele)
  D->>C: webhook deposit.paid (assinado)
  C->>C: verifica assinatura, dedup por Event-Id
  C->>D: GET /v1/deposits/dep_… (fetch-back)
  D-->>C: {status: paid, amount, external_id, player_ref}
  C->>C: confere com o que registrou e credita UMA vez
  C-->>D: 200

O saque é o espelho: você reserva o saldo do jogador antes de POST /withdrawals, o Dracma decide (automático ou revisão), e você só finaliza em paid — ou devolve a reserva em rejected, failed ou cancelled (saques.md).