Toda resposta da API segue o mesmo formato JSON. Sucesso ou erro, a estrutura é previsível.
Requisição processada com sucesso:
{
"success": true,
"data": {
// dados da resposta variam por endpoint
},
"request_id": "1a65b43fce4aa7c60f22d59d",
"timestamp": "2026-04-04T13:19:02Z"
}
| Campo | Tipo | Descrição |
|---|
success | boolean | Sempre true em respostas de sucesso |
data | object | Objeto contendo os dados da resposta |
request_id | string | ID único da requisição (útil para suporte) |
timestamp | string | Data/hora ISO 8601 da resposta |
Exemplo real — Consultar Saldo:
{
"success": true,
"data": {
"balances": [
{
"type": "fiat",
"currency": "BRL",
"available": "8446.75",
"blocked": "7682.19",
"pending": "0.00",
"total": "16128.94",
"price_usd": "0.19385044",
"price_brl": "1.00000000"
}
],
"wallet_total_usd": "106172.09817828",
"wallet_total_brl": "547701.08443680"
},
"request_id": "1a65b43fce4aa7c60f22d59d",
"timestamp": "2026-04-04T13:19:02Z"
}
Nota: Alguns endpoints legados (ex: /v2/pix/qrcode) retornam o payload diretamente sem o envelope success/data.
Quando algo dá errado, a resposta segue este formato:
{
"success": false,
"error": {
"code": "CODIGO_DO_ERRO",
"message": "Descrição amigável do erro",
"group": "VALIDATION",
"retryable": false
}
}
| Campo | Tipo | Descrição |
|---|
success | boolean | Sempre false em erros |
error.code | string | Código do erro (use para tratamento no código) |
error.message | string | Mensagem legível (pode exibir ao usuário) |
error.group | string | Grupo do erro: AUTH, VALIDATION, FINANCIAL, SYSTEM |
error.retryable | boolean | Se true, a requisição pode ser repetida automaticamente |
Alguns erros incluem detalhes extras:
{
"success": false,
"error": {
"code": "MISSING_REQUIRED_FIELD",
"message": "A required field is missing.",
"group": "VALIDATION",
"retryable": false,
"details": {
"fields": ["amount", "currency"]
}
}
}
Exemplo real — Token inválido:
{
"success": false,
"error": {
"code": "INVALID_TOKEN",
"message": "Invalid or malformed authentication token.",
"group": "AUTH",
"retryable": false
}
}
Exemplo real — Credenciais inválidas (OAuth):
{
"success": false,
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Invalid authentication credentials.",
"group": "AUTH",
"retryable": false
}
}
| Código | Significado | Quando acontece |
|---|
| 200 | OK | Operação síncrona concluída |
| 201 | Criado | Recurso criado |
| 202 | Aceito | Operação assíncrona aceita — confirmação chega via webhook (cashout, transfer, conversion) |
| 400 | Requisição Inválida | Dados enviados estão incorretos |
| 401 | Não Autenticado | Token inválido / expirado / sem assinatura HMAC |
| 403 | Proibido | Sem permissão, IP bloqueado ou conta sob revisão |
| 404 | Não Encontrado | Recurso não existe |
| 409 | Conflito | Duplicidade, limite excedido ou conflito de saldo |
| 415 | Tipo Não Suportado | Content-Type incorreto |
| 422 | Não Processável | Dados válidos mas não aceitos (saldo insuf., chave inválida) |
| 423 | Bloqueado | Conta bloqueada temporariamente |
| 428 | Pré-condição | Ação adicional necessária (ex: 2FA) |
| 429 | Muitas Requisições | Rate limit excedido |
| 500 | Erro Interno | Erro no servidor (contate o suporte) |
| 502 | Bad Gateway | Erro no provedor (PIX/blockchain) — retryable |
| 503 | Indisponível | Serviço temporariamente fora — retryable |
| Código | HTTP | Retryable | Descrição |
|---|
MISSING_AUTH_HEADER | 401 | não | Header Authorization ausente |
INVALID_AUTH_FORMAT | 401 | não | Formato do Authorization incorreto |
INVALID_CREDENTIALS | 401 | não | client_id/client_secret inválidos |
INVALID_TOKEN | 401 | não | Token Bearer inválido ou malformado |
TOKEN_EXPIRED | 401 | não | Token Bearer expirou — gere um novo |
UNAUTHORIZED | 403 | não | Sem autorização para este recurso |
FORBIDDEN | 403 | não | Acesso negado |
UNAUTHORIZED_IP | 403 | não | IP não está na whitelist da credencial |
INVALID_OTP | 401 | não | Código OTP/2FA incorreto |
CREDENTIAL_PENDING_ADMIN_ACTIVATION | 403 | não | Credencial aguardando ativação do admin |
| Código | HTTP | Retryable | Descrição |
|---|
MISSING_SIGNATURE | 401 | não | Header X-Signature ausente |
MISSING_TIMESTAMP | 401 | não | Header X-Timestamp ausente |
MISSING_NONCE | 401 | não | Header X-Nonce ausente |
INVALID_SIGNATURE | 401 | não | Assinatura HMAC não bate com hash recalculado |
INVALID_TIMESTAMP | 401 | não | Timestamp fora da janela ±5 min |
REPLAY_DETECTED | 401 | não | Nonce já usado nos últimos 5 min |
| Código | HTTP | Retryable | Descrição |
|---|
RATE_LIMIT_EXCEEDED | 429 | sim (após Retry-After) | Muitas requisições |
IP_BLACKLISTED | 403 | não | IP permanentemente bloqueado |
IP_BLOCKED_TEMPORARILY | 403 | sim (após 5 min) | IP bloqueado por 5 min após 5 falhas de auth |
SECURITY_BLOCKED | 423 | não | Bloqueio de segurança ativo |
ACCOUNT_UNDER_REVIEW | 403 | não | Conta sob análise — operação suspensa |
| Código | HTTP | Retryable | Descrição |
|---|
INVALID_PAYLOAD | 400 | não | Corpo da requisição inválido |
INVALID_JSON | 400 | não | JSON malformado |
MISSING_REQUIRED_FIELD | 400 | não | Campo obrigatório ausente — details.field |
INVALID_FORMAT | 422 | não | Formato de dado inválido |
INVALID_VALUE | 422 | não | Valor não aceito |
INVALID_AMOUNT | 422 | não | Valor monetário inválido (deve ser > 0, até 2 decimais) |
INVALID_CURRENCY | 422 | não | Moeda não suportada |
INVALID_PIX_KEY | 422 | não | Chave PIX inválida |
INVALID_SPLIT_CONFIG | 422 | não | Configuração de split inválida |
SELF_TRANSFER_BLOCKED | 400 | não | Não pode transferir para si mesmo |
UNSUPPORTED_CONTENT_TYPE | 415 | não | Content-Type não suportado |
UNSUPPORTED_CHAIN | 422 | não | Blockchain não suportada — details.supported lista chains aceitas |
UNSUPPORTED_CURRENCY | 422 | não | Moeda não suportada para esta operação |
| Código | HTTP | Retryable | Descrição |
|---|
INSUFFICIENT_BALANCE | 422 | não | Saldo insuficiente |
INSUFFICIENT_FUNDS | 422 | não | Fundos insuficientes para operação + fee |
BELOW_MIN_LIMIT | 409 | não | Valor abaixo do mínimo — details.min_* |
EXCEEDS_MAX_LIMIT | 409 | não | Valor acima do máximo — details.max_* |
LIMIT_EXCEEDED | 409 | não | Limite diário/mensal atingido |
| Código | HTTP | Retryable | Descrição |
|---|
PERMISSION_DENIED | 403 | não | Sem permissão para esta operação |
KYC_REQUIRED | 403 | não | Verificação KYC necessária |
DUPLICATE_RESOURCE | 409 | não | Recurso duplicado (email, phone, etc.) |
DUPLICATE_EXTERNAL_ID | 409 | não | external_id já utilizado |
PENDING_APPROVAL | 403 | não | Operação pendente de aprovação |
MISSING_FEE_CONFIG | 404 | não | Configuração de taxa não encontrada |
| Código | HTTP | Retryable | Descrição |
|---|
TRANSACTION_NOT_FOUND | 404 | não | Transação não encontrada |
TRANSACTION_ALREADY_DONE | 409 | não | Transação já processada |
INTERNAL_CONFLICT | 409 | sim | Conflito de concorrência no saldo — retry com nonce novo |
| Código | HTTP | Retryable | Descrição |
|---|
CREDENTIAL_NOT_FOUND | 404 | não | Credencial não encontrada |
CREDENTIAL_LIMIT_REACHED | 409 | não | Limite de credenciais atingido |
CREDENTIAL_ALREADY_ACTIVE | 409 | não | Credencial já está ativa |
| Código | HTTP | Retryable | Descrição |
|---|
INTERNAL_ERROR | 500 | sim | Erro interno do servidor |
PROVIDER_ERROR | 502 | sim | Erro no provedor (PIX/blockchain) |
SERVICE_UNAVAILABLE | 503 | sim | Serviço temporariamente fora |
Endpoints que retornam listas incluem metadados de paginação:
{
"success": true,
"data": {
"items": [ ... ],
"pagination": {
"page": 1,
"page_size": 50,
"count": 20,
"total": 150,
"total_pages": 8,
"has_next": true,
"has_prev": false
},
"summary": {
"total_transactions": 150,
"total_in": "1000.00",
"total_out": "500.00",
"total_fees": "15.00"
}
},
"request_id": "39316c1fcf4333e9f4726180",
"timestamp": "2026-04-04T13:20:30Z"
}
| Parâmetro | Tipo | Descrição |
|---|
page | integer | Página atual |
page_size | integer | Itens por página |
count | integer | Itens retornados nesta página |
total | integer | Total de registros |
total_pages | integer | Total de páginas |
has_next | boolean | Se existe próxima página |
has_prev | boolean | Se existe página anterior |
- Trate erros pelo
code, não pela message — mensagens podem mudar entre versões - Retry com backoff para
429 e 503. Nunca retry em outros 4xx - Logue
request_id em caso de erro — agiliza o suporte - Verifique
retryable antes de implementar retry automático - Não parse HTML — respostas são sempre JSON, mesmo em erros 500