Divergências conhecidas

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

Esta página lista, sem esconder, onde o Dracma de hoje faz algo diferente do Contrato v1 1.1.0, do documento OpenAPI servido ou de outras páginas do guia. As outras páginas descrevem o que a API faz hoje e apontam para cá quando há diferença.

O que é

Cada divergência tem um id estável (D-A1, D-D2...) e três colunas:

Coluna Conteúdo
Contrato diz o que o contrato 1.1.0, o OpenAPI ou um documento irmão afirma
Dracma faz hoje o comportamento real, conferido em 2026-10-18
Seu código o que o conector deve fazer para funcionar nos dois mundos: hoje e depois de uma correção. Quase sempre é seguir o comportamento mais restritivo

Uma divergência sai da lista, e vai para o histórico no fim, no mesmo momento em que o comportamento ou o contrato muda.

Quando usar

  • Ao implementar o conector, leia a coluna "Seu código" de cada linha da sua área.
  • Ao abrir um chamado com o suporte ou ao comentar uma regra no código, cite o id (D-W9, por exemplo).
  • Ao ver o Dracma agir diferente do contrato, procure o assunto aqui antes de supor um defeito.

Autenticação, transporte e erros

Id Contrato diz Dracma faz hoje Seu código
D-A1 §3.6: chave de uma operação com certificado de outra operação resulta em 401 mTLS é opcional e, quando ligado, o certificado é verificado na borda, com uma lista de certificados confiáveis por instância. A API não cruza chave × certificado nunca misture chave e certificado de operações diferentes; trate 401 como possível. Veja Rede, allowlist e mTLS
D-A2 5 req/s para /events e /reconciliation (por operação) balde de listagem de 5 req/s por chave para GET /deposits, GET /withdrawals, GET /events e GET /receipts (sem id). GET /reconciliation usa o balde geral de leitura pagine /events e /reconciliation devagar (no máximo 5 req/s); faça o fetch-back sempre por id
D-A3 o catálogo de erros não tem 413 corpo acima de 64 KiB resulta em 413 com code: validation_failed e reason: too_large trate 413 como um 4xx de validação
D-A4 o nonce é "32 hex" exige minúsculas (^[0-9a-f]{32}$); maiúsculas resultam em 401 invalid_signature gere hexadecimal em minúsculas
D-A5 §4.3: Dracma-Event-Id diferente do id do corpo resulta em 400 um documento irmão (SEGURANCA I8) diz 401; é ele que está errado responda 400
D-A6 não consta no contrato 20 falhas de assinatura por minuto do mesmo IP: as seguintes viram 429 rate_limited corrija a assinatura; nunca repita um 401 em laço
D-A8 503 psp_unavailable e outside_operating_hours não são emitidos; a indisponibilidade sai como 503 service_unavailable trate todo 503 igual: repita com a mesma chave depois do Retry-After
D-A9 limites por jogador não constam no contrato POST /deposits: 10 depósitos criados por jogador por hora. POST /withdrawals: 3 saques pedidos por jogador por hora. Acima disso: 429 rate_limited com Retry-After mostre "tente mais tarde" ao jogador; no saque, mantenha a reserva e repita com a mesma chave depois do Retry-After

Idempotência e corpo

Id Contrato diz Dracma faz hoje Seu código
D-I2 chave "em processamento" a reserva da chave dura 30 s; depois disso, outra execução pode assumir não faça duas chamadas concorrentes com a mesma chave

Depósitos

Id Contrato diz Dracma faz hoje Seu código
D-D2 POST /deposits/{id}/cancel cancela o depósito muda só o estado no Dracma. Não existe comando para cancelar a cobrança no PSP: o PIX continua pagável até expirar depósito cancelled com paid_amount preenchido: não credite e trate como exceção
D-D3 paid → refunded e paid → chargeback o gatilho existe só no sandbox: POST /v1/sandbox/deposits/{id}/refund e /chargeback (rotas aditivas; só de paid, outro estado resulta em 409; emitem deposit.refunded e deposit.chargeback). Em operação Real não há gatilho implemente o tratamento (débito por política, exceção para decisão humana) e teste-o no sandbox com essas rotas
D-D5 catálogo de eventos não existe deposit.created; o primeiro evento é deposit.pending com object_version 2 não espere evento de criação
D-D6 §6.1 não tem transição para pagamento depois de estado terminal pagamento em expired, cancelled ou failed: o estado não muda; paid_amount, paid_at e o pagador são gravados e o Dracma alerta nunca credite fora de paid; paid_amount em estado terminal é exceção para decisão humana
D-D7 REGRAS §12 (catálogo de motivos) emite também RULES_UNAVAILABLE e RULES_INVALID_RESPONSE, em review_reasons e em decision.reasons leitor tolerante: motivo desconhecido não muda nada
D-D8 Documento.type aceita PASSPORT, NATIONAL_ID e TAX_ID em PIX só CPF e CNPJ: os outros resultam em 422 document_invalid (depósito) ou em bloqueio (saque) em PIX envie só CPF ou CNPJ

Exigências por operação

Id Contrato diz Dracma faz hoje Seu código
D-R1 player.email e player.name opcionais; Moeda sem method_details; Problema.errors[].reason sem os motivos novos GET /currencies traz method_details[] (method, deposit_requirements, psp_notes), um campo aditivo que está no openapi.yaml servido (schema DetalheMetodo) e não no contrato 1.1.0. POST /deposits recusa com 400 (required_by_operation, format, max_length, reserved_domain_required) antes de criar objeto. O PSP de depósito da operação define quais campos são exigidos. player.email, se vier, é sempre validado; player.name acima de 120 resulta em 400 leia as exigências em GET /currencies; mande os campos; trate o 400 como recusa
D-R2 o corpo de depósito que o seu front monta (por exemplo {amount, method, cpf}) a operação pode exigir player.name e player.email no pedido ao Dracma o conector preenche nome e e-mail a partir do cadastro do jogador, no servidor, nunca do corpo que o front envia

Saques

Id Contrato diz Dracma faz hoje Seu código
D-W1 approved → processing = "enviado ao PSP" vira processing no primeiro retorno do PSP; envio recusado antes de sair (caixa, guarda de ambiente) deixa em approved e alerta approved pode durar; mantenha a reserva
D-W2 approved → cancelled permitido (cancelar "só antes de processing") com o comando de envio já publicado, cancelar resulta em 409 (evita pagar e devolver) trate 409 no cancelamento como "espere o desfecho"
D-W3 o diagrama §6.2 não desenha requested → cancelled permitido (o texto do §6.2 e o OpenAPI permitem) —
D-W4 Decisao.mode obrigatório em requested (consulta pendente ao diretório do PIX): mode: "manual", reasons: [], decided_at: null não conclua nada de mode em requested
D-W5 catálogo de eventos não existe evento público withdrawal.requested —
D-W6 DevolucaoBancaria completa: reason, return_fee, returned_amount, returned_at, reason_code em returned por PIX, o objeto return traz só reason_code, returned_amount e returned_at. reason_code pode ser unspecified, e returned_amount pode ser menor que o valor do saque (devolução parcial, que continua returned) não dependa de reason nem de return_fee; use returned_amount. Veja Saques
D-W7 ações de sandbox mudam o estado pay e fail respondem 200 com o estado atual; o desfecho chega por evento espere o webhook ou faça o fetch-back
D-W8 player.ip opcional sem player.ip o saque nunca é automático: under_review com OWNERSHIP_UNVERIFIED mande o IP do jogador em todo saque
D-W9 §2: POST /withdrawals responde 202 se o PSP demorar sempre 201: a criação não espera o PSP trate 201 e 202 igual
D-W10 motor de regras fora: erro (implícito) na criação do saque: 201 under_review com RULES_UNAVAILABLE (na dúvida, revisão). No depósito: 503 mantenha a reserva em under_review
D-W11 payout_currency diferente da moeda do valor: 422 fx_not_enabled purpose, fx_quote_id e payout_currency são aceitos e ignorados; o saque sai em BRL não envie esses campos em PIX

Reconciliação e leitura

Id Contrato diz Dracma faz hoje Seu código
D-C1 digest: itens ordenados por object_id empate (o mesmo object_id em dois itens) desempatado por kind crescente ordene por (object_id, kind)
D-C2 — não há vetor normativo do digest nos vetores de assinatura use o exemplo calculado em Reconciliação para conferir o seu código
D-C3 GET /rules sem currency usa a primeira moeda habilitada da operação —
D-C4 pending_in do caixa calculado pela API (depósitos recebidos e ainda em revisão ou retenção), não vem do livro use só para acompanhamento
D-C5 Reconciliacao.totals cobre os movimentos do dia não há total de return: o item return conta em count, mas não em nenhuma soma some os itens return à parte. Veja Reconciliação
D-C6 kind: return é "wire/SWIFT devolvido ao caixa" return é emitido hoje para depósito returned e para saque PIX returned. fee, recall e receipt não são emitidos trate return como movimento de PIX; aplique o leitor tolerante nos demais
D-C7 tarifa em Reconciliacao.items.fee e totals.fees fee do item é sempre null e totals.fees é "0": o Dracma não desconta tarifa do crédito não espere tarifa no relatório. As tarifas são por contrato

Webhooks

Id Contrato diz Dracma faz hoje Seu código
D-H2 omisso sobre redirecionamento 3xx conta como falha (reentrega) responda 2xx direto na URL cadastrada
D-H3 lista de IPs de saída publicada e assinada não há lista publicada nem endpoint, e o Dracma não garante IP fixo de origem assinatura e fetch-back são a defesa; não filtre o webhook por IP de origem

Sandbox e conformidade

Id Contrato diz Dracma faz hoje Seu código
D-S1 o OpenAPI do contrato 1.1.0 não declara Idempotency-Key nas rotas /sandbox/* a chave é exigida em todo POST. O openapi.yaml servido a declara mande uma chave nova em cada ação de sandbox
D-S2 §10: a suíte de conformidade fica numa pasta do repositório do operador de exemplo a suíte é do Dracma e é entregue no onboarding. Veja Sandbox —
D-S3 o OpenAPI do contrato 1.1.0 (cópia fiel) traz um servidor de teste local que não é do Dracma e um e-mail de exemplo de domínio real o openapi.yaml servido não tem esse servidor nem esse e-mail (usa jogador1@operador.test) ignore o servidor e o e-mail da cópia do contrato; fora de produção use TLD reservado (.test, .invalid, .example)
D-S4 a allowlist de IP vazia significa "sem acesso" a lista de IPs da operação é opcional: lista vazia significa sem restrição, em Teste e em Real. Com ao menos um IP, a chamada de outra origem recebe 403 ip_not_allowed cadastre a lista (altamente recomendado, principalmente em Real) quando o IP de saída for fixo. Veja Rede, allowlist e mTLS e IPs do conector

IP liberado é opcional

Sem IP liberado, nenhuma chamada é recusada por origem. Com IP liberado, a origem fora da lista recebe 403 ip_not_allowed. Proteja o conector com a assinatura, o escopo da chave e o segredo guardado só no servidor.

Resolvidas (histórico)

Id O que era Como ficou
D-D1 o executor não publicava charge.paid quando valor ou pagador divergiam (o depósito ficava pending) corrigido: o pagamento sempre chega com os valores reais e a API decide under_review
D-S0 a suíte de conformidade chamava /sandbox/* sem Idempotency-Key corrigido: a suíte gera uma chave nova em todo POST
D-H1 §5: backoff exponencial com jitter; o Dracma usava intervalos fixos, sem jitter corrigido: a reentrega soma um jitter positivo ao intervalo base (de 0 a 10 % do atraso). Veja Retentativas, skipped e DLQ
D-W6 (antes) paid → returned quando o banco devolve: só a ação de sandbox return aplicava; o executor não publicava devolução real corrigido em 2026-10-10: o Dracma consome a devolução do PSP e leva o saque pago a returned em operação Real, com o objeto return. A divergência atual de D-W6 é outra (campos da devolução)
D-OA rotas fx, receipts, recall e bank-transfers fora do documento servido (404 de rota inexistente) declaradas e implementadas no recorte PIX em 2026-10-02. Veja Rotas e campos reservados
D-O1 a D-O7 o documento OpenAPI servido citava um operador de exemplo pelo nome e um e-mail de domínio real; trazia servers com mTLS obrigatório e host sandbox.*; o 401 do webhook como "o Dracma não insiste"; rules.updated no enum de eventos; method_options e fx_quote_id no CriarDeposito; schema vazio em GET /sandbox/webhooks; Reconciliacao sem o caso de return corrigido na fonte (dracma_api, 2026-10-19): o documento servido descreve o comportamento real, e a cópia do guia foi sincronizada. Veja OpenAPI
D-I1 OpenAPI: operation_id no corpo "é ignorado se existir" corrigido no documento servido: ignorado só na raiz; aninhado resulta em 400 unknown_field. Continue sem enviá-lo
D-D4 OpenAPI CriarDeposito tinha method_options e fx_quote_id removidos do documento servido; a API continua recusando os dois com 400 unknown_field (existem só no contrato 1.1.0)
D-R3 os exemplos do OpenAPI usavam um e-mail de domínio real o documento servido usa jogador1@operador.test; fora de produção só TLD reservado, como antes
D-H4 o OpenAPI mostrava o 401 do webhook como "o Dracma não insiste" corrigido no documento servido: qualquer resposta que não seja 2xx é reentregue por até 72 h. Responda 2xx ao que já tratou
D-H5 o OpenAPI listava rules.updated entre os tipos de evento removido do documento servido; o Dracma nunca emitiu esse evento

Exemplos

Como citar uma divergência num chamado ao suporte:

Assunto: D-W9 em POST /v1/withdrawals
Operação: <operation_id>
Dracma-Trace-Id: <trace_id da resposta>
Esperado pelo contrato: 202 quando o PSP demora.
Observado: 201 com status approved.

Como proteger o conector nos dois mundos (D-W9, D-A8):

se status in (200, 201, 202): tratar como aceito e seguir pelo estado do objeto
se status == 503:             repetir com a mesma Idempotency-Key depois do Retry-After

Erros e casos de borda

  • A divergência não está aqui. Se o comportamento difere do guia e não há um id, abra um chamado com o trace_id da resposta.
  • O leitor tolerante vale para todas as linhas. Campo, estado ou motivo desconhecido nunca devem derrubar o seu conector nem mover dinheiro.
  • O contrato é a referência de semântica. Quando o texto de uma página do guia e o do contrato divergem em semântica, vale o contrato. Para a forma que a API aceita e devolve hoje, vale esta página somada às páginas da seção Referência.

Veja também