Erros e códigos
Os três envelopes emitidos
Seção intitulada “Os três envelopes emitidos”1. String simples (o mais comum)
Seção intitulada “1. String simples (o mais comum)”É o formato do helper de erro usado pela maior parte dos handlers.
{ "success": false, "error": "Address hash and blockchain are required."}2. Código como irmão de error
Seção intitulada “2. Código como irmão de error”Alguns handlers acrescentam um code ao lado de error, e não dentro dele.
{ "success": false, "code": "VALIDATION_FAILED", "error": "O campo external_id é obrigatório."}3. Objeto aninhado
Seção intitulada “3. Objeto aninhado”Usado principalmente pelo middleware de API key e por parte da superfície /vasp/*.
{ "success": false, "error": { "code": "api_key_rate_limit_exceeded", "message": "API key rate limit exceeded" }}Um consumidor defensivo faz assim:
function extrairCodigo(body) { if (!body) return null; if (typeof body.code === 'string') return body.code; // formato 2 if (body.error && typeof body.error === 'object') { // formato 3 return body.error.code ?? null; } return null; // formato 1}Onde fica o request_id
Seção intitulada “Onde fica o request_id”O identificador de correlação não vem no corpo do erro. Ele volta no header X-Request-ID da resposta, ecoando o que você enviou ou gerado pelo servidor. Guarde o header, e não um campo do JSON.
Mapeamento HTTP
Seção intitulada “Mapeamento HTTP”O status é a parte estável do contrato. Ramifique por ele.
4xx: erro do cliente
Seção intitulada “4xx: erro do cliente”| HTTP | Quando acontece | Ação recomendada |
|---|---|---|
| 400 | Corpo inválido, campo ausente, UUID malformado, enum fora do domínio | Corrija o payload, não retente |
| 401 | Sem credencial, credencial inválida, token expirado, ou MFA recente exigido | Reautentique. Se o code for MFA_STEP_UP_REQUIRED, refaça a verificação de MFA antes |
| 403 | Papel sem permissão, escopo de API key insuficiente, módulo não contratado | Ajuste papel, escopo ou entitlement. Não retente |
| 404 | Recurso inexistente ou pertencente a outro tenant | Não retente |
| 409 | Conflito de estado, recurso duplicado, Idempotency-Key reutilizada com corpo diferente, entrega não replayável |
Releia o estado antes de decidir |
| 422 | Regra de negócio recusou a operação | Leia a mensagem, corrija a intenção |
| 429 | Limite de chave, IP, tenant ou endpoint atingido | Respeite Retry-After (ver Rate Limits) |
5xx: erro do servidor
Seção intitulada “5xx: erro do servidor”| HTTP | Quando acontece | Ação recomendada |
|---|---|---|
| 500 | Falha inesperada. A mensagem pública é genérica de propósito, para não vazar interno | Retry com backoff. Persistindo, abra ticket com o X-Request-ID |
| 502 | Provedor externo respondeu erro | Retry com backoff, sem presumir fallback |
| 503 | Dependência indisponível, integração fora do ar, ou recurso desligado para o tenant | Retry com backoff. Em decisão de risco, a plataforma prefere segurar a operação a aprovar sem dado |
Códigos observados no servidor
Seção intitulada “Códigos observados no servidor”Estes code foram medidos no código do backend. A lista não é exaustiva e não é um contrato: nem toda resposta de erro traz code, e handlers diferentes usam vocabulários diferentes, inclusive minúsculo em parte da superfície /vasp/*.
| Code | Aparece em |
|---|---|
VALIDATION_FAILED |
Validação de corpo em rotas regulatórias e de governança |
INVALID_BODY, INVALID_ID, INVALID_REQUEST |
Parsing e validação de parâmetros |
NOT_FOUND |
Recurso inexistente no tenant |
UNAUTHORIZED |
Falta de credencial ou de permissão |
MFA_STEP_UP_REQUIRED |
Operação sensível exigindo MFA recente |
INVALID_TRANSITION |
Mudança de estado não permitida |
IDEMPOTENCY_CONFLICT, IDEMPOTENCY_KEY_REQUIRED |
Rotas com idempotência explícita |
STATE_CONFLICT |
Conflito de estado em fluxo regulatório |
api_key_rate_limit_exceeded |
Limite da chave de API estourado |
AUTH_RATE_LIMITED |
Limite de tentativas de autenticação |
SERVICE_ERROR, AUTH_UNAVAILABLE, AUDIT_UNAVAILABLE |
Dependência indisponível |
Estratégia de retry
Seção intitulada “Estratégia de retry”const RETRYABLE = new Set([408, 429, 500, 502, 503]);
async function callWithRetry(fn, maxAttempts = 4) { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (err) { if (!RETRYABLE.has(err.status) || attempt === maxAttempts) throw err; const retryAfter = err.headers?.['retry-after']; const delayMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : Math.min(1000 * Math.pow(2, attempt), 30000); await new Promise(r => setTimeout(r, delayMs + Math.random() * 500)); } }}Como reportar um erro
Seção intitulada “Como reportar um erro”Quando abrir ticket no suporte (dev-support@sentinexrisk.com), envie:
- O
X-Request-IDda resposta de erro - Timestamp da chamada (UTC)
- Endpoint mais método HTTP
tenant_id(não envie payload com PII)
Tempo de resposta SLA: P1 em menos de 1h, P2 em menos de 4h úteis, P3 em menos de 1 dia útil.