Errores y códigos de respuesta
Cada respuesta no-2xx devuelve un envelope estructurado. Misma forma para 4xx y 5xx — leélo una vez y manejá todos los errores de la API con un solo branch.
Envelope de error
Toda respuesta de error — 4xx o 5xx — viene con esta forma. Sin variantes, sin sorpresas. Si necesitás soporte, copiá el request_id en el ticket y vamos a poder trazar el request exacto.
{
"code": "invalid_input",
"message": "value must be a string.",
"field": "value"
}Campos del envelope
code— string · estable y machine-readable. Usalo para branchear en tu cliente.message— string · descripción human-readable en inglés por diseño. Si necesitás mensajes en español o portugués para usuarios finales, traducí en tu UI mapeando por code.field— Opcional. Nombra el campo de entrada que provocó el error.
Códigos de status HTTP
valid: false no es un error HTTP — devolvemos 200 con valid: false y razón legible. Los códigos abajo aplican a fallas de transporte, autenticación, schema o disponibilidad.
| Status | Significado | Cuándo | Qué hacer | error.code ejemplo |
|---|---|---|---|---|
| 200 | OK | Request válido y procesado. | Inspeccioná value.valid para el resultado de validación. | — |
| 400 | Bad Request | Falta un campo requerido, tipo incorrecto, JSON mal formado. | Revisá el error.code y el shape del body que estás mandando. | empty_batch · batch_too_large · invalid_input |
| 401 | Unauthorized | Header X-API-Key faltante o inválido. | Verificá el formato nd_… y que la key esté activa. | invalid_api_key |
| 429 | Too Many Requests | Excedido el quota de tu cuenta. | Honrá el header Retry-After. Ver /docs/rate-limits. | quota_exceeded · rate_limit_exceeded |
| 5xx | Bad Gateway · Unavailable · Timeout | Problema temporal de infraestructura o upstream. | Reintentá con exponential backoff + jitter. | internal_error |
Fallas por ítem
Una entrada que no se puede validar nunca interrumpe el lote. El resultado de ese ítem trae valid: false y un campo error con el motivo accionable. El resto de los ítems se devuelve igual.
| Endpoint | Ejemplo 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 |
Cuerpos de respuesta por estado
El éxito (200) devuelve { results: [...] } con un resultado por ítem (cada uno con su valid y, si falla, error). Los errores de lote devuelven { 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."
}Estrategia de retries
Los códigos 5xx y 429 son seguros para reintentar — son fallas transitorias o de capacidad. Implementá exponential backoff con jitter para evitar thundering herd en recuperaciones.
Los códigos 4xx (excepto 429) NO se deben reintentar. Son fallas de request — el request va a fallar igual si lo mandás de nuevo sin cambios. Fijate primero el error.code y corregí el request antes de reintentar.
Retry seguro: 5xx, 429. NO retry: 400, 401, 403, 404, 422. Para 429, honrá Retry-After.