Problemas de integração

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

Roteiro de diagnóstico para os problemas mais comuns ao chamar a API: 401 por relógio ou corpo, 403, 404, 409, 429 e 503 em laço, e ambiente errado. Parta do sintoma, confirme a causa e aplique a correção.

O que é

Cada seção começa pelo que você vê (o status e o code) e termina no que fazer. A API confere as coisas numa ordem fixa (Autenticação HMAC), e o primeiro problema é o que volta: use isso para eliminar causas.

Problemas de webhook estão em Problemas comuns de webhook; problemas de dinheiro (saldo, estado parado), em Runbook de dinheiro.

Quando usar

Quando uma chamada falha e você não sabe por quê, e antes de abrir um chamado. Guarde o Dracma-Trace-Id de toda resposta que não seja 2xx: com ele o suporte acha a requisição.

Como funciona

Passo zero: reproduza os vetores

Antes de qualquer outra hipótese, faça o seu código produzir os três vetores de vetores-assinatura.json (mesma assinatura, byte a byte). Se não produz, o problema é local e não de rede nem do Dracma. Imprima o pedido canônico com cat -A ou equivalente: um $ no fim da última linha é um \n que não pode existir.

401: autenticação

flowchart TD A[401] --> B{code} B -->|timestamp_out_of_window| C[Relógio, unidade ou formato do timestamp] B -->|invalid_signature| D[Segredo, key_id, bytes do corpo, caminho ou query] B -->|replayed_nonce| E[Nonce repetido, inclusive em retry] B -->|unknown_key| F[Tipo da chave x host, ou chave revogada]

timestamp_out_of_window

Causa provável Como confirmar Correção
Relógio do servidor fora de ±300 s Compare o cabeçalho Date da resposta (vem também no erro) com date -u no seu servidor Ative o NTP (chronyc tracking); alerte desvio acima de 5 s
Timestamp em milissegundos O valor tem 13 dígitos floor(agora_ms / 1000)
Formato fora do canônico Tem +, espaço, zero à esquerda, casa decimal ou notação científica Inteiro simples, sem formatação
Assinou com um timestamp e enviou outro O cabeçalho difere do usado no canônico Calcule uma vez e reuse na assinatura e no cabeçalho
Relógio do contêiner diferente do host (VM pausada, snapshot restaurado) O desvio aparece só em uma máquina Sincronize ao restaurar

invalid_signature: é o código mais genérico, de propósito (o Dracma não revela se a chave existe).

Causa provável Como confirmar Correção
Segredo errado, de outra chave, ou com \n ou espaço no fim Reproduza o vetor com o segredo lido do seu cofre Leia o segredo sem a quebra de linha; confira o key_id
Dracma-Key-Id digitado errado Chave "inexistente" e assinatura errada voltam o mesmo 401 Copie o key_id do painel
Corpo diferente do assinado Só POST falha; reserializou o JSON, mudou a ordem das chaves ou o espaçamento Serialize uma vez; assine e envie os mesmos bytes
Biblioteca HTTP recodifica o corpo (compressão, charset) Compare o sha256 do corpo no seu log com o do pedido de rede (proxy de depuração) Envie o corpo cru, sem compressão
Caminho sem /v1, ou com host na frente O canônico tem /deposits em vez de /v1/deposits Assine o caminho completo
Query reordenada ou decodificada Só GET com parâmetros falha Assine a URL exatamente como enviada (curl --path-as-is)
Método em minúsculas O canônico tem post Maiúsculas
Nonce com maiúscula ou com menos de 32 caracteres O nonce não casa ^[0-9a-f]{32}$ openssl rand -hex 16 ou equivalente
Segredo usado decodificado (hexadecimal ou base64) O vetor só passa decodificando Use os bytes da própria string
Um proxy ou balanceador seu muda o caminho ou o corpo A assinatura passa em chamada direta e falha atrás do proxy Assine o que sai do proxy ou desligue a reescrita

Sobre 429 no lugar de 401: depois de 20 falhas de assinatura por minuto do mesmo IP, o Dracma passa a responder 429 rate_limited. Pare o laço, corrija a causa e espere o Retry-After.

replayed_nonce

Causa provável Correção
O retry reutiliza o nonce da primeira tentativa Gere o nonce dentro da função que monta cada tentativa
Dois processos usam um gerador com a mesma semente Use o gerador do sistema (crypto/rand, random_bytes)
O mesmo pedido é enviado duas vezes por um proxy de repetição Desligue o retry automático do proxy e deixe a repetição para o conector

unknown_key

Causa provável Como confirmar Correção
Tipo da chave não bate com o host (key_test_ na API Real, ou o contrário) O prefixo da chave e o host da sua base Use o par chave-host certo (Ambientes, tipos de operação e hosts)
Chave revogada O painel mostra a chave como Revogada Crie outra
Dracma-Key-Id ausente ou mal formado O cabeçalho some em algum proxy Verifique os cabeçalhos que chegam

403: autorização

Um 403 quer dizer que a autenticação passou: a assinatura está certa.

code Causa Correção
insufficient_scope A chave não tem o escopo da rota; ou você usou um método que a API não tem (PUT, DELETE, OPTIONS); ou fez POST em rota que não existe Compare a rota com a tabela de escopos; use a chave do componente certo
operation_suspended Operação suspensa pelo Dracma FAQ: operação suspensa
ip_not_allowed Chave válida usada de origem fora da lista de IPs da operação Use o IP público de saída do conector. Se o IP mudou ou é dinâmico, peça a inclusão do novo IP (aprovação e espera de 24 h) ou remova a lista; veja IPs do conector

400, 404, 409 e 422

Sintoma Causa Correção
400 validation_failed com unknown_field Campo que o schema não tem (inclusive status, version, paid_amount) Remova o campo; a API não aceita campo "extra"
400 com field: Idempotency-Key POST sem Idempotency-Key, ou com menos de 16 caracteres 16 a 128 caracteres [A-Za-z0-9_.:-]
400 com field: amount Valor como número, decimal ou com zeros à esquerda Money (Convenções HTTP)
400 com reason: required_by_operation A operação exige um campo que o contrato deixa opcional Mande o campo; consulte GET /currencies
400 com reason: reserved_domain_required E-mail de jogador real em operação Teste Use .test, .invalid ou .example
404 not_found em objeto que existe O objeto é de outra operação, ou o id tem outro formato Confira a chave e o id
404 em rota que existe GET em rota só POST, ou caminho sem /v1 Método e caminho
404 sem corpo Caminho fora de /v1/*, ou /v1/sandbox/* em operação Real Corrija a base; sandbox só em Teste
409 idempotency_key_reused Mesma chave com outro corpo, rota ou query Reenvie os bytes originais, ou use chave nova e external_id novo (operação nova)
409 duplicate_external_id O external_id já existe Leia existing; concilie em vez de criar outro
409 invalid_state_transition O estado atual não permite a ação (cancelar saque já enviado, por exemplo) GET do objeto e decida
422 Recusa de negócio (limite, lista, documento, caixa) Erros; não repita igual

429 e 503 em laço

Um laço de repetição sem espera é a causa mais comum de 429 e piora o 503.

  1. Leia o Retry-After e espere esse tempo, no mínimo. Sem o cabeçalho, use backoff exponencial com jitter (1 s, 2 s, 4 s, até 60 s).
  2. Descubra qual balde estourou. Escrita (50/s, rajada 100), leitura (100/s por chave), listagem (5/s) ou jogador (10 depósitos e 3 saques por hora) — Limites e quotas. Retry-After de minutos é balde de jogador.
  3. Ponha uma fila e um teto de concorrência no conector: dispare a uma taxa abaixo do teto, nunca em rajada de lote.
  4. Use um disjuntor. Depois de N falhas seguidas, pare por um intervalo e teste com GET /v1/ping antes de voltar.
  5. Mantenha a mesma Idempotency-Key em toda repetição de um POST. 429 e 5xx liberam a chave; a repetição nunca duplica.
  6. 503 repetido por minutos é problema do Dracma ou de uma dependência dele: junte o Dracma-Trace-Id de duas ou três respostas e abra chamado (Suporte). Não crie objetos novos para "driblar": consulte por external_id (Idempotência e repetição).
  7. 503 com Retry-After: 5 em operação Teste pode ser a queda simulada ligada por POST /sandbox/outage: desligue com {"down": false}.

Ambiente errado

Sintomas típicos: 401 unknown_key com a chave certa; 404 em /v1/sandbox/...; depósito que "não aparece" no painel; ou dinheiro movendo quando você achava que era teste.

  1. Chame GET /v1/ping e leia environment: sandbox é operação Teste; production é operação Real.
  2. Compare com o prefixo da chave (key_test_ ou key_live_) e com o host da sua base (Ambientes, tipos de operação e hosts).
  3. Confira se o painel que você olha é o do mesmo ambiente (hml e produção são painéis distintos).
  4. Guarde uma configuração por ambiente (base, key_id, segredo, segredo de webhook) e nunca misture.

Dinheiro real

Operação Real cobra e paga de verdade, inclusive no hml. Se você não tem certeza do tipo da chave, rode GET /v1/ping antes de qualquer POST.

Timeouts e conexão

  • Timeout de cliente: 10 s. O depósito pode levar cerca de 7 s e voltar 202; o saque é sempre 201.
  • Timeout não é falha. Repita com a mesma Idempotency-Key. Se desistir, consulte por external_id antes de decidir.
  • Resposta que não é JSON (página de erro de proxy, 413 sem corpo) vem da entrada pública ou da rede: trate como erro de transporte.
  • TLS: use TLS 1.2 ou superior e valide o certificado do host; não desligue a verificação para "fazer funcionar".

Exemplos

Checagem rápida de relógio, antes de mexer em qualquer outra coisa (a resposta de erro também traz Date):

curl -sS -o /dev/null -D - "$DRACMA_BASE_URL/ping" | grep -i '^date:'
date -u

Se as duas horas diferirem em mais de alguns segundos, o relógio é o problema.

Diagnóstico de assinatura com o shell, usando as funções de exemplos/shell/lib.sh:

source exemplos/shell/lib.sh
dracma_canonico 1790000000 0123456789abcdef0123456789abcdef POST /v1/deposits corpo.json | cat -A
dracma_assinar "$(cat segredo.txt)" 1790000000 0123456789abcdef0123456789abcdef POST /v1/deposits corpo.json

Compare as saídas com o vetor 1. Qualquer $ no fim da última linha do canônico, ou uma assinatura diferente, mostra onde está a diferença.

Erros e casos de borda

  • Funciona direto e falha atrás de um proxy ou API gateway seu: o proxy reescreve caminho, query ou corpo depois de você assinar. Assine no último salto.
  • Funciona em GET e falha em POST: quase sempre o corpo assinado não é o enviado, ou falta Idempotency-Key.
  • Funciona uma vez e depois dá replayed_nonce: nonce fixo ou semente repetida.
  • Intermitente, com timestamp_out_of_window: relógio com deriva ou VM pausada.
  • Só 401 na primeira chamada do dia: chave rotacionada e segredo antigo no cofre.
  • Depois de 20 falhas, tudo vira 429: o IP está bloqueado por falhas de assinatura; corrija a causa e espere.
  • Nada disso: abra um chamado com Dracma-Trace-Id, horário em UTC, operation_id, rota e code. Não envie o segredo da chave.

Veja também