Regras (API)

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

A API deixa você ler as regras vigentes da sua operação e propor uma mudança. Ela nunca altera uma regra: a proposta fica pendente até outra pessoa aprová-la no painel. Esta página descreve GET /v1/rules, POST /v1/rules/change-requests, o uso de If-Match e ETag e os erros.

O que é

Rota Escopo operationId Resposta
GET /v1/rules read obterRegras 200 com o conjunto de regras vigente (ConjuntoDeRegras) e o cabeçalho ETag
POST /v1/rules/change-requests rules:propose pedirMudancaDeRegras 202 com {"id": "chg_...", "status": "pending_approval"}

O conjunto de regras define os limites de depósito e saque, o multiplicador do saque automático, o horário do automático e outros critérios de revisão. Quem aplica as regras é o motor do Dracma, em cada pedido. Os códigos que o motor devolve (decision.reasons e os 422) estão em Decisão, limites e regras.

Quando usar

  • Ler quando precisar dos limiares: mínimo e máximo por transação, teto do automático, horário. A página de limites do jogador mostra o que cabe para um jogador; GET /v1/rules mostra a regra da operação inteira.
  • Propor quando quiser mudar um limite pela API, em vez de pedir ao suporte. Quem tem a chave com o escopo rules:propose pode propor; a mudança só vigora depois da aprovação no painel.

Os valores de fábrica dos limites não são publicados aqui. Leia os da sua operação com GET /v1/rules.

Como funciona

Ler: GET /v1/rules

A API devolve o conjunto vigente da operação da chave, no corpo, com o cabeçalho ETag. O motor guarda um conjunto por operação e a consulta usa a primeira moeda habilitada na operação (veja Ping e moedas). O parâmetro currency não existe nesta rota.

  • O ETag é um valor opaco, entre aspas. Guarde-o exatamente como veio, aspas incluídas: você o envia de volta em If-Match.
  • A API não responde 304: toda leitura devolve o corpo inteiro.
  • Operação sem moeda habilitada ou sem conjunto de regras: 404 not_found.
  • Motor de regras fora: 503 service_unavailable, repetível.

Campos principais do ConjuntoDeRegras:

Campo Tipo Significado
version inteiro versão do conjunto. Sobe a cada mudança aprovada
timezone texto fuso IANA da operação (por exemplo America/Sao_Paulo). Define dia, janelas e horário do automático
currencies objeto uma chave por moeda; o valor traz as regras daquela moeda (tabela abaixo)
first_withdrawal_manual booleano o primeiro saque pago de cada jogador passa por revisão humana
pix_key_change_cooldown_hours inteiro carência, em horas, para uma chave PIX nova do jogador
require_payer_matches_player booleano exige que o pagador do depósito seja o jogador
auto_hours objeto ou null {"from": "HH:MM", "to": "HH:MM"}, na hora local da operação, ou null quando não há restrição de horário

Em currencies.<código>:

Campo Tipo Significado
auto_multiplier texto multiplicador X do saque automático: o automático cobre até X vezes o que o jogador depositou. "0" desliga o automático
deposit_min, deposit_max texto mínimo e máximo por depósito, na menor unidade
withdrawal_min, withdrawal_max texto mínimo e máximo por saque, na menor unidade
auto_max_per_withdrawal texto teto de um saque no automático
auto_max_per_day texto teto do dia no automático
dual_approval_above texto acima deste valor, o saque exige duas pessoas na revisão
max_withdrawals_per_day inteiro quantidade de saques por dia

O corpo traz mais grupos de configuração do que os listados (janelas, velocidade, destino, pagador, calendário do automático e outros). Trate-os como opacos: leia, mantenha e devolva intactos numa proposta. Campo desconhecido é ignorado na leitura (leitor tolerante).

Reservado no contrato

O grupo bank_transfers do conjunto de regras, com fx e os limites de wire e SWIFT, é aceito e versionado, mas o motor não o aplica: não há trilho bancário nem câmbio habilitado hoje. Veja Rotas e campos reservados.

Propor: POST /v1/rules/change-requests

Uma proposta leva o cabeçalho If-Match e um corpo com dois campos:

Campo Obrigatório Regra
rules sim um objeto com o conjunto de regras proposto
justification sim texto não vazio, até 1000 caracteres

Cabeçalhos: If-Match (obrigatório), com o ETag exato do último GET /v1/rules; e Idempotency-Key (todo POST leva).

Fluxo:

sequenceDiagram participant C as Seu conector participant D as API do Dracma participant P as Painel C->>D: GET /v1/rules D-->>C: 200 conjunto + ETag C->>C: altera uma cópia do conjunto C->>D: POST /v1/rules/change-requests (If-Match = ETag) alt ETag igual ao vigente D-->>C: 202 {id: chg_..., status: pending_approval} Note over D,P: nada vigora ainda P->>P: uma pessoa da equipe aprova (afrouxar também espera um prazo) P->>D: nova versão vigente else ETag diferente D-->>C: 412 etag_mismatch C->>D: GET /v1/rules e refaça a proposta end
  1. Leia GET /v1/rules e guarde o corpo e o ETag.
  2. Altere uma cópia completa do conjunto. Não mande só o campo que mudou: blocos ausentes na proposta são preenchidos pelo Dracma com o valor de fábrica, o que pode desfazer configuração que você não quis mexer.
  3. Envie POST /v1/rules/change-requests com If-Match igual ao ETag lido.
  4. A resposta 202 traz o id da proposta (chg_ seguido de 32 caracteres hexadecimais) e status: "pending_approval". A regra vigente não mudou. A API nunca altera uma regra.
  5. A aprovação acontece no painel, por uma pessoa da sua equipe com permissão para isso. Mudança que afrouxa limites também espera um prazo antes de vigorar. Veja Regras, listas e emergência.
  6. Quando a aprovação sai, GET /v1/rules passa a devolver o conjunto novo, com version maior e outro ETag.

A API não tem rota para consultar o estado de uma proposta. Acompanhe pelo painel, ou leia GET /v1/rules e compare version e ETag.

Exemplos

GET /v1/rules, resposta 200 (os valores abaixo são ilustrativos, não são valores de fábrica):

HTTP/1.1 200 OK
Content-Type: application/json
ETag: "<etag>"
{
  "version": 4,
  "timezone": "America/Sao_Paulo",
  "currencies": {
    "BRL": {
      "auto_multiplier": "1",
      "deposit_min": "1500",
      "deposit_max": "3000000",
      "withdrawal_min": "2500",
      "withdrawal_max": "3000000",
      "auto_max_per_withdrawal": "400000",
      "auto_max_per_day": "800000",
      "dual_approval_above": "1500000",
      "max_withdrawals_per_day": 4
    }
  },
  "first_withdrawal_manual": true,
  "pix_key_change_cooldown_hours": 48,
  "require_payer_matches_player": true,
  "auto_hours": { "from": "08:00", "to": "22:00" }
}

Proposta:

POST /v1/rules/change-requests HTTP/1.1
Host: api.example.test
Content-Type: application/json; charset=utf-8
If-Match: "<etag>"
Idempotency-Key: rules-2026-10-18-0001
Dracma-Key-Id: key_test_01J9EXEMPLO
Dracma-Timestamp: 1790000300
Dracma-Nonce: 0123456789abcdef0123456789abcdef
Dracma-Signature: v1=<assinatura>

{
  "rules": { "version": 4, "timezone": "America/Sao_Paulo", "currencies": { "BRL": { "...": "o conjunto completo, com a mudança" } } },
  "justification": "Reduzir o teto diário do automático durante a campanha."
}

Resposta 202:

{
  "id": "chg_0192a3b40c6d7e8f9a0b1c2d3e4f5a6b",
  "status": "pending_approval"
}

Resposta 412 quando o ETag ficou velho:

{
  "type": "https://docs.dracma.test/errors/etag_mismatch",
  "title": "etag_mismatch",
  "status": 412,
  "code": "etag_mismatch",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "retryable": false
}

Erros e casos de borda

Rota Situação Resposta
POST If-Match ausente 400 validation_failed, field: If-Match, reason: required
POST corpo que não é JSON válido, ou tem campo fora de rules e justification 400, field: body, reason: invalid_json
POST rules ausente ou que não é objeto 400, field: rules, reason: required
POST justification vazia ou com mais de 1000 caracteres 400, field: justification, reason: length
POST o motor recusa o conjunto proposto (forma, campo desconhecido ou valor inválido) 400, field: rules, reason: invalid
POST If-Match diferente do ETag vigente 412 etag_mismatch
GET e POST operação sem conjunto de regras 404 not_found
GET e POST motor de regras fora 503 service_unavailable, repetível
POST chave sem o escopo rules:propose 403 insufficient_scope
  • 412 não é erro do seu código. Alguém aprovou uma mudança, ou o ETag caducou. Releia GET /v1/rules, refaça a mudança sobre o conjunto novo e proponha de novo. Não repita o POST com o mesmo If-Match.
  • O If-Match é comparado como texto, com as aspas. Mande o valor exatamente como o GET devolveu.
  • A proposta registra a chave que a enviou (a operação e o autor vêm da credencial, nunca do corpo).
  • Os limiares de revisão dependem do conjunto. Depois de propor, não mude o seu código esperando o efeito: ele só existe depois da aprovação.

Veja também