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.
{
"code": "invalid_input",
"message": "value must be a string.",
"field": "value"
}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.field— Opcional. Nomeia o campo de entrada que causou o erro.
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. | empty_batch · batch_too_large · invalid_input |
| 401 | Unauthorized | Header X-API-Key ausente ou inválido. | Confere o formato nd_… e que a key está ativa. | invalid_api_key |
| 429 | Too Many Requests | Excedeu a cota da sua conta. | Honra o header Retry-After. Ver /docs/rate-limits. | quota_exceeded · rate_limit_exceeded |
| 5xx | Bad Gateway · Unavailable · Timeout | Problema temporário de infraestrutura ou upstream. | Tenta de novo com exponential backoff + jitter. | internal_error |
Falhas por item
Uma entrada que não pode ser validada nunca interrompe o lote. O resultado desse item traz valid: false e um campo error com o motivo acionável. O resto dos itens é devolvido normalmente.
| Endpoint | Exemplo de error |
|---|---|
| tax-ids · accounts | check digit does not match |
| tax-ids | unsupported type for country AR |
| accounts | account checksum is not verified |
| emails | typo in domain: did you mean gmail.com? |
| phones | not a valid phone number for BR |
Corpos de resposta por status
O sucesso (200) devolve { results: [...] } com um resultado por item (cada um com seu valid e, se falhar, error). Os erros de lote devolvem { code, message, field? }.
{
"results": [
{
"id": "a",
"country": "AR",
"type": "cuit",
"valid": true,
"normalized": "20123456786",
"formatted": "20-12345678-6"
},
{
"id": "b",
"country": "AR",
"type": "cuit",
"valid": false,
"error": "check digit does not match"
}
]
}{
"code": "empty_batch",
"message": "The `items` array must contain at least one item."
}{
"code": "invalid_api_key",
"message": "Missing or invalid X-API-Key header."
}{
"code": "quota_exceeded",
"message": "This batch of 250 requests exceeds the remaining monthly quota."
}{
"code": "internal_error",
"message": "Unexpected server error. Retry after 5s with jitter."
}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.