Convenções da API

Regras válidas para todos os endpoints sob /v1/*. Cada endpoint individual pode acrescentar regras específicas, mas nunca contradiz o que está aqui.

URL base e versionamento

https://api.sacador.com.br/v1/<recurso>

A versão (v1) está no path. Quebras de contrato → nova versão (v2); adições retrocompatíveis (novos campos, novos endpoints) entram na v1 sem aviso.

Autenticação

Todas as requisições exigem header:

Authorization: Bearer sct_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json

Detalhes do token, criação e revogação: ver authentication.md.

Content type

  • Requisições com corpo (POST/PATCH/PUT): envie Content-Type: application/json ou application/x-www-form-urlencoded. Os dois são aceitos.
  • Respostas: sempre application/json; charset=utf-8.

Status codes

CodeQuando
200 OKGET, PATCH, POST/cancel e POST/pay_off bem-sucedidos. Também o POST repetido com a mesma reference nos endpoints idempotentes, ver Idempotência
201 CreatedPOST que criou o recurso
204 No ContentDELETE bem-sucedido — corpo vazio
400 Bad RequestJSON malformado
401 UnauthorizedHeader Authorization ausente, mal-formado ou com token desconhecido/revogado
403 ForbiddenToken válido, mas a conta dona do token está com status diferente de active (overdue, locked, canceled) ou ainda não teve a verificação de cadastro (KYC) aprovada. Nos endpoints do PDV (vendas, créditos do cliente, baixa por repasse), também quando a conta não ativou o módulo PDV
404 Not FoundRecurso inexistente ou pertencente a outra conta — o Sacador não diferencia os dois casos, para não vazar a existência de registros de outras contas
409 Conflictreference já usada com dados diferentes, nos endpoints idempotentes
422 Unprocessable ContentFalha de validação, parâmetro obrigatório ausente ou regra de negócio recusada
429 Too Many RequestsLimite de requisições excedido — ver seção Rate limit
500 Internal Server ErrorErro inesperado no Sacador. Retentar com backoff

Formato de erro

Toda resposta 4xx retorna JSON em um destes formatos:

Erros de validação ou autorização lógica (422):

{
  "status": 422,
  "errors": [
    "Descrição não pode ficar em branco",
    "CPF inválido"
  ]
}

errors é sempre um array de strings (já localizadas em português). Cada string é uma mensagem independente e exibível ao usuário final.

Erros de autenticação, autorização e roteamento (401, 403, 404):

{
  "status": 401,
  "message": "Unauthorized"
}

Recusas de regra de negócio (409 e alguns 422): o mesmo corpo { status, message }, às vezes com um terceiro campo, code:

{
  "status": 422,
  "message": "Contato não encontrado nesta conta.",
  "code": "contact_not_found"
}

message é texto em português para exibir ou registrar em log e pode mudar de redação. code é um identificador estável, para o seu sistema decidir o que fazer sem interpretar texto. Ele só aparece nos casos que o integrador precisa distinguir dos demais erros do mesmo status; quando não vier, trate o erro pelo status. Os valores de hoje:

codeStatusEndpointSignificado
contact_not_found422POST/v1/store_creditsO contato informado não existe nesta conta. Cadastre ou vincule o contato e reenvie
settlement_contact_missing422POST/v1/receivable_settlementsA loja não configurou o contato pagador da baixa. Retentar não resolve até a loja ajustar a configuração

Novos valores de code podem surgir sem mudança de versão. Trate um code desconhecido como um erro comum daquele status.

Rate limit (429):

{
  "error": "Excedido o limite de requisições. Por favor, tente novamente mais tarde."
}

Acompanhado do header Retry-After: .

Paginação

Todos os endpoints GET /v1/ (listagens) são paginados. Os parâmetros de paginação são query params — não use headers.

Query params

ParamDefaultValor aceitoComportamento fora da faixa
page1Inteiro ≥ 1Valores menores que 1 ou inválidos são tratados como página 1
per_page25Inteiro entre 1 e 100Valores > 100 são limitados a 100; 0, negativo ou não-numérico cai para o default 25

Exemplo:

GET /v1/contacts?page=2&per_page=50

Response headers

Toda listagem retorna os mesmos quatro headers:

HeaderSignificado
X-Total-CountTotal de registros (já considerando os filtros aplicados)
X-PagePágina retornada nesta resposta
X-Per-PageTamanho efetivo da página (já clampado para [1, 100])
X-Total-PagesNúmero total de páginas

Os totais consideram apenas os registros da sua conta — o isolamento é aplicado antes da contagem.

Estratégia recomendada

1. Inicialize page = 1
2. Faça GET com page atual
3. Processe os items
4. Se page >= X-Total-Pages → fim
5. Senão page += 1 e volte a 2

Para sincronizações periódicas, prefira combinar paginação com os filtros de data (start_created_at / end_created_at quando disponíveis) para limitar a varredura ao intervalo novo.

Rate limit

Duas contagens rodam ao mesmo tempo sobre todas as rotas /v1/*. A requisição é barrada quando qualquer uma das duas estoura:

ContadorLimiteChave
Por origem300 requisições por minutoIP de onde a requisição partiu
Por credencial600 requisições por minutoToken usado no Authorization
  • O contador por credencial existe para que um token replicado em várias máquinas não escape do limite por IP.
  • Quando excedido: 429 com header Retry-After em segundos. Espere e retente — não há janela deslizante, o contador zera no início do próximo minuto-cheio.
  • Se múltiplos sistemas integrados saem do mesmo IP, o limite por origem é compartilhado entre eles. Para volumes maiores, distribua a integração em IPs distintos ou abra um canal com o Sacador.

Conta ainda não verificada

A API só responde a contas com a verificação de cadastro (KYC) aprovada. Enquanto a aprovação não sai, toda requisição — em qualquer rota /v1/*, com token válido — recebe 403:

{
  "status": 403,
  "message": "Esta funcionalidade fica disponível depois que a documentação da conta for enviada e aprovada."
}

Não há limite reduzido, modo restrito nem sandbox: ou a conta está aprovada e a API funciona inteira, ou não está e nada funciona. O Sacador aplica limites menores a contas não verificadas (quantidade de contatos, de tags e de cobranças, e teto de valor por cobrança), mas eles valem para o uso pela tela — uma integração nunca chega a esbarrar neles, porque não passa do 403.

Verifique a conta antes de começar a integrar: o envio dos documentos e o status ficam em /account_verification.

Filtros e busca

Endpoints de listagem que aceitam s (search) interpretam a string como LIKE substring do lado do servidor. Não há sintaxe especial — s=joão retorna registros contendo "joão" no campo indexado para busca daquele recurso. Veja cada endpoint para saber em qual campo a busca é aplicada.

Multi-tenancy

Toda requisição é automaticamente restrita à conta dona do token. Você não consegue:

  • Ler, criar, atualizar ou apagar registros de outra conta.
  • Atribuir account_id em POST/PATCH — esse parâmetro é silenciosamente ignorado e sempre forçado para a conta autenticada.
  • Referenciar IDs de outra conta em FKs (contact_id, tag_id, bank_rule_id, bank_account_id). Tentativas retornam 422 com erro de associação.

Recursos de outra conta acessados por ID direto retornam 404, idêntico ao caso de ID inexistente.

Idempotência

Dois endpoints aceitam uma chave de idempotência no corpo, o campo reference, única por conta:

  • POST/v1/store_credits: mesma reference com o mesmo contato e valor devolve 200 com o registro original; com outros dados, 409.
  • POST/v1/receivable_settlements: mesma reference com o mesmo cutoff_at devolve 200 com o estado da baixa original (ou 202, retomando uma baixa que falhou); com outro corte, 409.

Nesses dois, retentar depois de um timeout é seguro: reenvie o mesmo corpo com a mesma reference.

Os demais endpoints não implementam chave de idempotência. Em caso de timeout, antes de retentar um POST, consulte o GET correspondente (busque pelo your_code que você gerou, por exemplo) para detectar criação duplicada.

Boas práticas

  • Idempotência: ver a seção própria.
  • Backoff em 5xx e 429: use exponencial com jitter. Em 429, respeite o Retry-After.
  • Não dependa de campos não documentados. Campos não listados na referência podem mudar formato ou ser removidos sem aviso.
  • Versione seus payloads. O Sacador pode adicionar campos nas respostas. Faça parsing tolerante a chaves desconhecidas.
  • Use your_code como chave de correlação com o seu sistema, e busque por ele depois — é um campo livre indexável (até 20 chars).