Pular para o conteúdo

Erros e códigos

É o formato do helper de erro usado pela maior parte dos handlers.

{
"success": false,
"error": "Address hash and blockchain are required."
}

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."
}

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
}

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.

O status é a parte estável do contrato. Ramifique por ele.

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)
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

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
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));
}
}
}

Quando abrir ticket no suporte (dev-support@sentinexrisk.com), envie:

  1. O X-Request-ID da resposta de erro
  2. Timestamp da chamada (UTC)
  3. Endpoint mais método HTTP
  4. 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.