Erros e códigos de resposta
Toda resposta não-2xx devolve um envelope estruturado. Mesma forma pra 4xx e 5xx — leia uma vez e maneje todos os erros da API com um único branch.
Envelope de erro
Toda resposta de erro — 4xx ou 5xx — vem com essa forma. Sem variantes, sem surpresas. Se precisar de suporte, copia o request_id no ticket e a gente consegue rastrear o request exato.
{
"error": {
"code": "invalid_input",
"message": "value must be a string",
"request_id": "req_a1b2c3d4e5f6g7"
}
}Campos do envelope
code— string · estável e machine-readable. Use pra branchear no seu cliente.message— string · descrição human-readable em inglês por design. Se precisar de mensagens em português ou espanhol pro usuário final, traduz na sua UI mapeando por code.request_id— string · combina com o header X-Request-Id da resposta. Logamos do nosso lado por 30 dias — inclua em qualquer report pro suporte.
Códigos de status HTTP
valid: false não é um erro HTTP — devolvemos 200 com valid: false e um motivo legível. Os códigos abaixo se aplicam a falhas de transporte, autenticação, schema ou disponibilidade.
| Status | Significado | Quando | O que fazer | error.code exemplo |
|---|---|---|---|---|
| 200 | OK | Request válido e processado. | Inspecione value.valid pro resultado da validação. | — |
| 400 | Bad Request | Falta um campo obrigatório, tipo errado, JSON mal formado. | Confere o error.code e o shape do body que está mandando. | invalid_input · missing_required_field |
| 401 | Unauthorized | Header X-API-Key ausente ou inválido. | Confere o formato nd_… e que a key está ativa. | unauthorized · invalid_api_key |
| 403 | Forbidden | Endpoint não autorizado pro seu scope. | Fala com o suporte se você deveria ter acesso a esse endpoint. | forbidden |
| 404 | Not Found | URL inexistente. | Revisa os paths dos endpoints (/v1/verify/…). | not_found |
| 422 | Unprocessable Entity | Input com shape errado pro endpoint (ex. mandar um email pra /verify/tax-id). | Use Smart Parse ou o endpoint correto pro tipo de dado. | wrong_endpoint_for_input |
| 429 | Too Many Requests | Excedeu a cota do seu plano. | Honra o header Retry-After. Ver /docs/rate-limits. | rate_limited |
| 500 | Internal Server Error | Bug do nosso lado. | Tenta de novo com backoff exponencial; reporta com o request_id. | internal_error |
| 502/503/504 | Bad Gateway · Unavailable · Timeout | Problema temporário de infraestrutura ou upstream. | Tenta de novo com exponential backoff + jitter. | bad_gateway · unavailable · timeout |
Códigos de warning
Quando um endpoint processa parcialmente ou detecta algo suspeito, devolve warnings no array warnings junto com um 200 OK. Não são erros — são sinais pra sua UI ou pipeline.
| Code | Quando aparece | O que significa |
|---|---|---|
| UNKNOWN_TAX_ID | O formato do tax ID não bate com nenhum país conhecido. | Devolvido com valid: false quando Smart Parse não consegue detectar o país. Peça pro usuário confirmar o país e reenviar. |
| LOW_CONFIDENCE | Smart Parse fez um best-guess de roteamento com confidence < 0.5. | Passa um country_hint pra desambiguar e subir o confidence. |
| AMBIGUOUS_MATCH | Múltiplos tipos bateram no input com confidence parecido. | Pega o primeiro candidato (mais provável) ou olha o array warnings pra ver todos os candidatos. |
| INVALID_CHECKSUM | Formato ok mas o dígito verificador não bate. | Provavelmente um typo do usuário. Mostra erro inline na sua UI e pede pra revisar. |
| COMPONENTS_IGNORED | Mandou full_name e first_name juntos — full_name venceu. | Olha o diff entre source e normalized pra ver o que foi descartado. |
| DISPOSABLE_DOMAIN | O email vem de um provedor descartável conhecido. | Mostra como soft warning — não necessariamente bloqueie, depende do seu caso de uso. |
| RESERVED_RANGE | O número de telefone está num range reservado (ex. 555 nos EUA). | Rejeita como dado de teste — esses números não são alcançáveis numa rede real. |
X-Request-Id
Toda resposta — sucesso ou erro — inclui o header X-Request-Id com um ID único formato req_… que também aparece dentro do envelope de erro.
Logamos request_id do nosso lado por 30 dias. Quando abrir um ticket em hello@normadata.io ou reportar um bug, copia o request_id — sem ele a gente não consegue rastrear o request exato nos nossos logs.
Estratégia de retries
Os códigos 5xx e 429 são seguros pra tentar de novo — são falhas transitórias ou de capacidade. Implementa exponential backoff com jitter pra evitar thundering herd em recuperações.
Os códigos 4xx (exceto 429) NÃO devem ser tentados de novo. São falhas de request — o request vai falhar do mesmo jeito se você mandar de novo sem mudar nada. Olha primeiro o error.code e corrige o request antes de tentar de novo.
Retry seguro: 5xx, 429. NÃO retry: 400, 401, 403, 404, 422. Pra 429, honra Retry-After.