Pular para o conteúdo

Erros e códigos

Toda resposta de erro segue o mesmo schema, independente do endpoint. Trate erros pelo error.code (string estável), nunca pelo error.message (texto pode mudar).

{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Limite de 100 requisições/minuto excedido. Tente novamente em 23s.",
"details": {
"limit": 100,
"window_seconds": 60,
"retry_after_seconds": 23
},
"request_id": "req_01HVZX9YQB7M3J2K5N8P1R4T6W"
}
}
CampoDescrição
codeString estável UPPER_SNAKE_CASE. Use para lógica de tratamento
messageTexto pt-BR (ou en-US se Accept-Language: en-US) para humanos
detailsObjeto contextual (campo inválido, retry-after, etc). Varia por código
request_idID de correlação. Sempre informe ao suporte
HTTPCodeCausaAção recomendada
400VALIDATION_FAILEDCampo ausente ou tipo erradoCorrija payload, não retente
400MALFORMED_JSONJSON inválidoCorrija sintaxe
400INVALID_ADDRESSEndereço crypto não-canônicoNormalize antes (lowercase ETH, base58 BTC)
400UNSUPPORTED_BLOCKCHAINBlockchain não suportadaUse enum: BITCOIN, ETHEREUM, TRON, SOLANA, POLYGON, BSC
401UNAUTHENTICATEDSem header ou token inválidoReautentique
401TOKEN_EXPIREDJWT expirouUse /auth/refresh
401MFA_STEP_UP_REQUIREDOperação sensível exige MFA recenteFaça /auth/mfa/verify antes
403FORBIDDEN_SCOPEAPI key sem escopo necessárioGere nova key com escopo correto
403MODULE_NOT_ENTITLEDTenant não tem o módulo no planoUpgrade ou ative módulo no admin
404RESOURCE_NOT_FOUNDRecurso inexistente ou em outro tenantNão retente
409IDEMPOTENCY_CONFLICTMesma Idempotency-Key com body diferenteUse chave nova
409DUPLICATE_RESOURCERecurso único já existe (ex: external_id)Trate como sucesso silencioso
409STATE_CONFLICTOperação inválida no estado atual (ex: resolver alerta já resolvido)Releia o estado
422BUSINESS_RULE_FAILEDRegra de negócio bloqueou (ex: KYC pendente)Veja details.rule_id
429RATE_LIMITEDLimite por tenant/IP/endpoint atingidoRespeite Retry-After
HTTPCodeCausaAção recomendada
500INTERNAL_ERRORBug inesperadoRetry com backoff exponencial. Se persistir, abra ticket com request_id
502UPSTREAM_UNAVAILABLEBureau externo (Exato, Chainalysis) foraRetry após 30s; nosso fallback geralmente cobre em <60s
503SERVICE_DEGRADEDModo degradado (alguma integração caiu)Decisão pode vir REVIEW em vez de APPROVE; reprocesse depois
504UPSTREAM_TIMEOUTBureau passou de 2sIdem 502
const RETRYABLE = new Set([408, 429, 500, 502, 503, 504]);
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) * 1000
: Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise(r => setTimeout(r, delayMs + Math.random() * 500));
}
}
}
CodeQuando apareceSignificado
KYC_TIER_INSUFFICIENTTransação acima do limite para o tier do clienteFaça upgrade KYC (ENHANCED) antes
SANCTIONS_HITCliente ou contraparte em lista OFAC/ONU/COAFNão desbloquear sem revisão compliance
TRAVEL_RULE_REQUIREDTransação ≥ R$ 1.000 entre VASPsEnvie IVMS101 antes de liquidar
COAF_REPORTING_TRIGGEREDTransação dispara SAR automáticoAguarde envio em até 24h

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

  1. request_id da resposta de erro
  2. Timestamp da chamada (UTC)
  3. Endpoint + método HTTP
  4. tenant_id (não envie payload com PII!)

Tempo de resposta SLA: P1 < 1h, P2 < 4h úteis, P3 < 1 dia útil.