Depósitos

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

Um depósito é uma intenção de cobrança PIX: você o cria, o Dracma devolve o copia-e-cola, o jogador paga e o Dracma avisa por webhook. Esta página descreve as quatro rotas (criar, consultar, listar e cancelar), a validação do corpo, os erros na ordem em que a API os confere e os campos que o objeto Deposito realmente devolve.

O que é

Rota Escopo operationId Resposta de sucesso
POST /v1/deposits deposits:write criarDeposito 201 com o PIX pronto, ou 202 com o depósito ainda em created
GET /v1/deposits read listarDepositos 200 com {data, next_cursor}
GET /v1/deposits/{id} read obterDeposito 200 com o Deposito
POST /v1/deposits/{id}/cancel deposits:write cancelarDeposito 200 com o Deposito em cancelled

Hoje só existe PIX em BRL. Qualquer outro método do enum Metodo responde 400 method_not_enabled.

method Situação
pix disponível
card, crypto, boleto, bank_transfer, wire, swift não disponível: 400 method_not_enabled
qualquer outro valor (por exemplo "ted") 400 validation_failed com errors[0] = {field: "method", reason: "enum"}

Não disponível

O Dracma não oferece hoje cartão, cripto, boleto, transferência bancária, wire nem SWIFT para depósito. A tentativa responde 400 method_not_enabled e não cria nada. O único método é pix, na moeda BRL.

O Dracma credita o valor cheio no depósito pago. O objeto Deposito não traz tarifa descontada: o campo fee do contrato não é devolvido (veja a seção "Objeto Deposito" mais abaixo). As tarifas do contrato com o Dracma estão em Tarifas.

Quando usar

O fluxo recomendado, de ponta a ponta:

sequenceDiagram participant C as Seu conector participant D as API do Dracma participant W as Webhook do Dracma C->>C: grava o depósito local (external_id, amount, player_ref) C->>D: POST /v1/deposits (Idempotency-Key = external_id) D-->>C: 201 pending com instructions.pix.copy_paste C->>C: mostra o copia-e-cola até instructions.pix.expires_at Note over C,W: o jogador paga no banco W->>C: POST deposit.paid (assinado) C->>C: verifica assinatura e deduplica C->>D: GET /v1/deposits/{id} (fetch-back) D-->>C: 200 status paid C->>C: credita uma vez, pelo valor que você gravou
  1. Grave o depósito no seu lado antes de chamar o Dracma.
  2. Chame POST /v1/deposits com Idempotency-Key igual ao external_id. Use timeout de cliente de 10 s.
  3. Em erro de rede, 5xx ou 429, repita com a mesma chave. Se perdeu a resposta, consulte GET /v1/deposits?external_id=.
  4. Mostre instructions.pix.copy_paste ao jogador até instructions.pix.expires_at.
  5. Ao receber deposit.paid, verifique a assinatura, deduplique e faça o fetch-back com GET /v1/deposits/{id}. Só credite quando o status lido for paid.

Nunca credite pelo corpo do webhook. O efeito de cada estado no seu livro está em Ciclo do depósito.

Como funciona

Criar: POST /v1/deposits

O corpo é um objeto JSON com estas chaves. Qualquer chave fora da lista é recusada.

Campo Obrigatório Regra
external_id sim seu id do depósito, ^[A-Za-z0-9_.:-]{1,64}$, único por operação
player.external_ref sim seu id do jogador, mesmo formato, opaco e imutável (nunca e-mail, telefone ou CPF)
player.document sim type em CPF, CNPJ, PASSPORT, NATIONAL_ID, TAX_ID; CPF/CNPJ só dígitos (11 a 14); country ISO 3166 alfa-2 em maiúsculas
player.name depende da operação até 120 caracteres
player.email depende da operação validado sempre que vier. Veja "Exigências por operação"
player.ip, player.device_id depende da operação informativos, entram na análise de risco. Veja "Exigências por operação"
player.birth_date, player.kyc_level não informativos
amount sim Money com amount maior que zero
method sim pix
expires_in_seconds não de 300 a 86400. Padrão 1800
locale não por exemplo pt-BR
metadata não até 20 chaves, valores texto

Para PIX o documento do jogador só pode ser CPF ou CNPJ. Os outros tipos passam na validação de forma, mas voltam 422 document_invalid.

O documento do jogador fica fixado no primeiro uso do external_ref. Mandar outro documento para o mesmo external_ref depois resulta em 422 document_mismatch. Veja Dados e privacidade.

Validação estrita. O corpo é recusado com 400 validation_failed, antes de qualquer efeito, quando tem:

Problema errors[].reason
campo desconhecido, inclusive status, version, paid_amount ou operation_id aninhado unknown_field
chave JSON repetida em qualquer nível duplicate_key
UTF-8 inválido invalid_utf8
JSON inválido syntax
conteúdo depois do objeto trailing_data
tipo errado type
external_id, external_ref, número de documento ou país em formato inválido format
tipo de documento fora da lista enum
expires_in_seconds fora da faixa, ou metadata com mais de 20 chaves range
amount ausente ou zero, method ausente required

operation_id na raiz do corpo é descartado em silêncio: o tenant e a operação vêm só da credencial. Não o envie. method_options e fx_quote_id existem só no contrato 1.1.0 (o documento OpenAPI servido não os traz) e não são aceitos em depósito PIX: voltam unknown_field (veja Divergências conhecidas). Corpo acima de 64 KiB volta 413.

Exigências por operação

Alguns PSPs exigem dados que o contrato deixa opcionais. O Dracma escolhe o PSP de depósito de cada operação no onboarding e declara as exigências em GET /v1/currencies (method_details[].deposit_requirements). Veja Ping e moedas.

Quando a operação exige um campo e ele vem ausente, em branco ou só com espaços, a API recusa antes de criar qualquer coisa e antes do motor de regras:

errors[].field errors[].reason Quando
o campo exigido, por exemplo player.email required_by_operation a operação exige e o campo não veio
player.email format fora de local@dominio.tld, ou com nome de exibição. Vale sempre que o e-mail vier
player.email max_length mais de 254 caracteres
player.email reserved_domain_required operação Teste: o e-mail só pode ter TLD reservado (.test, .invalid, .example)
player.name max_length mais de 120 caracteres. Vale sempre
  • É um 4xx: não cria objeto, jogador nem evento. A mesma Idempotency-Key devolve o mesmo 400 por 30 dias. Depois de corrigir o cadastro, crie com external_id novo.
  • Mande o e-mail cadastrado do jogador, lido do seu servidor. Nunca um e-mail digitado no pedido de depósito e nunca um inventado.
  • Em operação Teste, e-mail real de um cadastro copiado de produção recebe reserved_domain_required. Reescreva os e-mails do seu ambiente de teste (por exemplo jogador1@operador.test). Se a operação não exige e-mail, não envie o campo.
  • Mande sempre player.name: operações reais costumam exigi-lo.
  • Em operação Real o domínio do e-mail não é restrito, só o formato.

Resposta 201: PIX pronto

O depósito é criado e o PSP já devolveu o PIX. status vem pending, version vem 2 e instructions.pix traz copy_paste (o BR Code, que é o conteúdo do QR) e expires_at. qr_code_png_base64 vem quando o PSP o fornece; se não vier, gere o QR a partir do copy_paste.

  • Use o instructions.pix.expires_at devolvido, não o prazo que você pediu: o PSP pode ajustar o prazo.
  • Em operação Teste o BR Code é sintético e nenhum dinheiro real se move.
  • 201 com status: "failed" também existe: o PSP recusou a cobrança antes da resposta. O objeto foi criado e é conclusivo (veja failure_code). Não repita; crie outro depósito com external_id novo se fizer sentido.

Dinheiro real

Em uma operação Real, o PIX devolvido é um PIX de verdade: o pagamento move dinheiro real. Faça seus testes de ponta a ponta numa operação Teste.

Resposta 202: aceito, PIX ainda não disponível

Se o PSP demorar mais que o orçamento de resposta da API (cerca de 7 s), o Dracma responde 202 com status: "created", version: 1 e instructions: null. Não é erro. Espere o webhook deposit.pending ou consulte GET /v1/deposits/{id} até o status ser pending, e então mostre o PIX. Não crie outro depósito para tentar de novo.

Consultar: GET /v1/deposits/{id}

É o fetch-back: o estado autoritativo que você lê antes de creditar. 200 devolve o Deposito. Um id que não existe nesta operação responde 404 not_found. Objeto de outra operação também é 404, nunca 403, e um id fora do formato dep_ seguido de letras e números também.

Antes de creditar, confira o que veio contra o que você gravou na criação: external_id, amount.amount, amount.currency e player_ref têm de ser idênticos. Se algo divergir, não credite, marque para revisão e alerte.

Listar: GET /v1/deposits

Escopo read. Usa o balde de listagem do rate limit (veja Limites e quotas).

Parâmetro Uso
external_id acha o depósito pelo seu id. É o jeito de saber o destino de um POST cuja resposta se perdeu
player_ref depósitos de um jogador
status filtra por estado. Valor fora do enum de StatusDeposito responde 400 com reason: format
updated_since RFC 3339. Devolve itens com updated_at maior ou igual ao instante dado
cursor o next_cursor da página anterior. Cursor inválido responde 400 com reason: format
limit de 1 a 200. Padrão 50. Valor fora da faixa responde 400 com reason: format

A resposta é {"data": [Deposito, ...], "next_cursor": "dep_..." | null}. A ordem é a do id do depósito, que segue a ordem de criação, e não a de updated_at. next_cursor é o id dep_... do último item da página e vira null na última. Para uma varredura incremental, guarde o maior updated_at visto e use updated_since com ele (o >= repete o último item, então deduplique). Veja Paginação e filtros.

Assine o caminho com a query exatamente como enviada.

Cancelar: POST /v1/deposits/{id}/cancel

Escopo deposits:write. Corpo vazio. Idempotency-Key obrigatória.

  • Só cancela de pending. A resposta é 200 com o objeto em cancelled. Se ele já estava cancelled, a resposta é o mesmo 200, sem evento novo.
  • Em created, paid, expired, under_review ou qualquer outro estado, a resposta é 409 invalid_state_transition. Em created, espere pending e cancele depois.
  • Cancelar no Dracma não cancela a cobrança no PSP. O PIX continua pagável até o prazo do PSP. Se alguém pagar depois, o estado não muda e o paid_amount é gravado: não credite e trate como exceção. Veja Política de exceções de dinheiro e a divergência D-D2 em Divergências conhecidas.

Expiração

O Dracma expira sozinho o depósito pending depois de expires_at mais 2 minutos de folga (o job roda a cada 30 s). A folga existe porque o PSP ainda pode aceitar o pagamento logo depois do prazo. Ao expirar sai o webhook deposit.expired.

Objeto Deposito

O Deposito é o mesmo no 201, no GET e no data.object do webhook. A API devolve 16 campos e nenhum outro. Os campos da v1.1.0 do contrato (rail, received_amount, receipts, fee, fees, fx, compliance, expected_settlement_date, return) existem no contrato 1.1.0, mas não no documento OpenAPI servido, e nunca são devolvidos em depósito. Não dependa deles.

Campo Tipo Devolvido hoje? Conteúdo
id texto sim id do Dracma, dep_ seguido de 32 caracteres hexadecimais. Trate como opaco
external_id texto sim o seu id
status texto sim estado atual
version inteiro sim começa em 1 (created) e sobe a cada transição. Ignore estado com version menor ou igual à já aplicada
amount Money sim valor cobrado
paid_amount Money ou null sim valor pago. Em paid é igual a amount. Pode vir preenchido em estado terminal sem crédito (pagamento tardio)
method texto sim pix
player_ref texto sim o seu player.external_ref
payer objeto ou null sim quem pagou. Preenchido em paid e under_review. Veja abaixo
instructions objeto ou null sim null em created. Depois, {"pix": {copy_paste, expires_at, qr_code_png_base64?}}
failure_code texto ou null sim motivo técnico em failed. Lista aberta
review_reasons lista de texto sim motivos de under_review. Vazia ([]) fora de revisão
created_at, updated_at texto sim RFC 3339 em UTC com segundos, sem fração, por exemplo 2026-10-18T15:04:05Z
paid_at texto ou null sim instante do pagamento
expires_at texto ou null sim fim do prazo do PIX
rail, received_amount, receipts, fee, fees, fx, compliance, expected_settlement_date, return — não reservados da v1.1.0 (só no contrato; fora do OpenAPI servido)

Reservado no contrato

fee, fees, fx, compliance, return e os demais campos da v1.1.0 estão no schema Deposito do OpenAPI, mas a API não os preenche em depósito PIX. A tarifa não é descontada do valor creditado (veja Tarifas).

payer. Traz document (type, number, country), name e matches_player, que é true quando o documento de quem pagou bate com o do jogador. Use-o só para exibir e auditar; a decisão de crédito é o status.

status. O enum StatusDeposito tem 13 valores:

status Como o depósito chega aqui Alcançável em PIX hoje
created aceito, PIX ainda não gerado sim
pending PIX gerado, aguardando pagamento sim
under_review dinheiro recebido com divergência (pagador diferente, valor diferente, pago após o prazo ou pagador não confirmado) sim
paid pago com valor exato e pagador conferido, ou aprovado na revisão sim
expired prazo vencido sem pagamento sim
cancelled cancelado por você sim
failed o PSP recusou a cobrança sim
returned devolvido na revisão: o depósito não foi aceito e nunca foi creditado sim
refunded, chargeback depois de paid só no sandbox, por ação simulada
pending_compliance, frozen, paid_partial acréscimos da v1.1.0 não: nenhum depósito chega a esses estados hoje

Estado desconhecido é não-terminal e não move dinheiro no seu lado: confira de novo pelo fetch-back (leitor tolerante). A máquina de estados completa e o efeito de cada estado no seu livro estão em Ciclo do depósito.

review_reasons. Lista aberta de códigos em maiúsculas, por exemplo PAYER_MISMATCH, PAYER_UNKNOWN, AMOUNT_MISMATCH, PAID_AFTER_EXPIRY, RULES_UNAVAILABLE e RULES_INVALID_RESPONSE. Código desconhecido não muda nada: o que manda é o status. O significado de cada um e o que o painel faz com ele está em Ciclo do depósito.

Exemplos

Pedido de criação (os valores de assinatura são ilustrativos; o algoritmo está em Autenticação HMAC):

POST /v1/deposits HTTP/1.1
Host: api.example.test
Content-Type: application/json; charset=utf-8
Idempotency-Key: dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b
Dracma-Key-Id: key_test_01J9EXEMPLO
Dracma-Timestamp: 1790000000
Dracma-Nonce: 0123456789abcdef0123456789abcdef
Dracma-Signature: v1=<assinatura>

{
  "external_id": "dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
  "player": {
    "external_ref": "0192a3b4-0000-7000-8000-000000000001",
    "document": { "type": "CPF", "number": "12345678909", "country": "BR" },
    "name": "Jogador Teste",
    "email": "jogador1@operador.test",
    "ip": "203.0.113.10"
  },
  "amount": { "amount": "5000", "currency": "BRL" },
  "method": "pix",
  "expires_in_seconds": 1800
}

Resposta 201, PIX pronto:

{
  "id": "dep_0192a3b40c6d7e8f9a0b1c2d3e4f5a6b",
  "external_id": "dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
  "status": "pending",
  "version": 2,
  "amount": { "amount": "5000", "currency": "BRL" },
  "paid_amount": null,
  "method": "pix",
  "player_ref": "0192a3b4-0000-7000-8000-000000000001",
  "payer": null,
  "instructions": {
    "pix": {
      "copy_paste": "00020126...6304ABCD",
      "expires_at": "2026-10-18T15:30:00Z"
    }
  },
  "failure_code": null,
  "review_reasons": [],
  "created_at": "2026-10-18T15:00:00Z",
  "updated_at": "2026-10-18T15:00:01Z",
  "paid_at": null,
  "expires_at": "2026-10-18T15:30:00Z"
}

Resposta 202, PIX ainda não disponível:

{
  "id": "dep_0192a3b40c6d7e8f9a0b1c2d3e4f5a6c",
  "external_id": "dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6c",
  "status": "created",
  "version": 1,
  "amount": { "amount": "5000", "currency": "BRL" },
  "paid_amount": null,
  "method": "pix",
  "player_ref": "0192a3b4-0000-7000-8000-000000000001",
  "payer": null,
  "instructions": null,
  "failure_code": null,
  "review_reasons": [],
  "created_at": "2026-10-18T15:00:00Z",
  "updated_at": "2026-10-18T15:00:00Z",
  "paid_at": null,
  "expires_at": "2026-10-18T15:30:00Z"
}

O mesmo depósito depois de pago, lido no fetch-back:

{
  "id": "dep_0192a3b40c6d7e8f9a0b1c2d3e4f5a6b",
  "external_id": "dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
  "status": "paid",
  "version": 3,
  "amount": { "amount": "5000", "currency": "BRL" },
  "paid_amount": { "amount": "5000", "currency": "BRL" },
  "method": "pix",
  "player_ref": "0192a3b4-0000-7000-8000-000000000001",
  "payer": {
    "document": { "type": "CPF", "number": "12345678909", "country": "BR" },
    "name": "Jogador Teste",
    "matches_player": true
  },
  "instructions": {
    "pix": {
      "copy_paste": "00020126...6304ABCD",
      "expires_at": "2026-10-18T15:30:00Z"
    }
  },
  "failure_code": null,
  "review_reasons": [],
  "created_at": "2026-10-18T15:00:00Z",
  "updated_at": "2026-10-18T15:07:41Z",
  "paid_at": "2026-10-18T15:07:40Z",
  "expires_at": "2026-10-18T15:30:00Z"
}

Um depósito em revisão porque o pagador não é o jogador. Não credite:

{
  "id": "dep_0192a3b40c6d7e8f9a0b1c2d3e4f5a6d",
  "external_id": "dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6d",
  "status": "under_review",
  "version": 3,
  "amount": { "amount": "5000", "currency": "BRL" },
  "paid_amount": { "amount": "5000", "currency": "BRL" },
  "method": "pix",
  "player_ref": "0192a3b4-0000-7000-8000-000000000002",
  "payer": {
    "document": { "type": "CPF", "number": "98765432100", "country": "BR" },
    "name": "Outra Pessoa",
    "matches_player": false
  },
  "instructions": {
    "pix": {
      "copy_paste": "00020126...6304ABCD",
      "expires_at": "2026-10-18T15:30:00Z"
    }
  },
  "failure_code": null,
  "review_reasons": ["PAYER_MISMATCH"],
  "created_at": "2026-10-18T15:00:00Z",
  "updated_at": "2026-10-18T15:09:10Z",
  "paid_at": "2026-10-18T15:09:09Z",
  "expires_at": "2026-10-18T15:30:00Z"
}

Recusa por exigência da operação (400, sem objeto criado):

{
  "type": "https://docs.dracma.test/errors/validation_failed",
  "title": "validation_failed",
  "status": 400,
  "code": "validation_failed",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "retryable": false,
  "errors": [
    {
      "field": "player.email",
      "message": "obrigatório nesta operação (exigência do PSP de cash-in; ver GET /v1/currencies)",
      "reason": "required_by_operation"
    }
  ]
}

Listagem para achar um depósito pelo seu id:

GET /v1/deposits?external_id=dep_0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b&limit=10 HTTP/1.1

Erros e casos de borda

Erros da criação, na ordem em que a API os confere

# HTTP code Quando O que fazer
1 400 validation_failed corpo inválido (veja a tabela de validação) corrija o pedido; não repita igual
2 429 rate_limited mais de 10 depósitos criados por jogador por hora mostre "tente mais tarde"; repita com a mesma chave depois do Retry-After
3 400 validation_failed (field: method, reason: enum) method fora do enum Metodo corrija
4 400 method_not_enabled method do enum, mas diferente de pix não ofereça o método
5 422 document_invalid tipo de documento diferente de CPF e CNPJ revise o cadastro do jogador
6 409 duplicate_external_id o external_id já existe (com outra Idempotency-Key); o objeto vem em existing use o existing; não crie outro
7 400 currency_not_enabled ou method_not_enabled moeda ou método não habilitado nesta operação configuração do onboarding
8 400 validation_failed (required_by_operation, format, max_length, reserved_domain_required) exigência da operação corrija o cadastro; external_id novo
9 422 amount_below_minimum, amount_above_maximum, document_invalid, document_mismatch, player_blocked, destination_blocked, velocity_exceeded recusa do motor de regras, sem objeto mostre mensagem genérica ao jogador; não revele a causa
10 503 service_unavailable motor de regras, cofre de dados ou banco fora repita com a mesma Idempotency-Key depois do Retry-After

Notas:

  • document_invalid no passo 9 cobre CPF ou CNPJ com dígito verificador errado. velocity_exceeded no depósito cobre muitos depósitos criados e não pagos numa janela. Os limiares são da regra da operação: consulte Regras (API) e Decisão, limites e regras.
  • Recusa 4xx não cria objeto. A mesma Idempotency-Key devolve a mesma recusa, guardada por 30 dias. Se você usa Idempotency-Key = external_id, tentar de novo depois de uma recusa exige external_id novo. Veja Idempotência e repetição.
  • Erro de rede, timeout, 5xx e 429 não são respostas conclusivas: repita com a mesma chave.

Erros das outras rotas

Rota Situação Resposta
GET /v1/deposits/{id} não existe nesta operação, ou id fora do formato 404 not_found
GET /v1/deposits status, updated_since, limit ou cursor inválidos 400 validation_failed com o campo em errors[]
POST /v1/deposits/{id}/cancel estado diferente de pending e de cancelled 409 invalid_state_transition
POST /v1/deposits/{id}/cancel não existe nesta operação 404 not_found
qualquer sem o escopo exigido 403 insufficient_scope

Casos de borda

  • Pagamento depois de expirar ou cancelar. Se o PIX é pago com o depósito já em expired, cancelled ou failed, o estado não muda: o Dracma grava paid_amount, paid_at e o pagador e alerta. Para você, paid_amount preenchido num estado sem crédito é exceção: não credite. Veja Ciclo do depósito.
  • under_review não credita. O dinheiro entrou, mas há divergência. Espere o desfecho (paid ou returned).
  • Estado e evento novos. Aplique o leitor tolerante: campo, estado ou motivo desconhecido nunca devem derrubar o seu parser nem mover dinheiro.
  • Ambiente. Em operação Teste, e-mail com domínio real é recusado (reserved_domain_required) e nenhum dinheiro se move.

Veja também