De cero al primer 200 OK en 60 segundos.
Una API. Un schema JSON. Un único formato de error para todos los identificadores de Sudamérica. Esta es la guía mínima para llegar de cero a tu primera respuesta.
Tu primer request
Mandá un array items con value, country y type a /v1/validate/tax-ids. Recibís un results con un objeto por ítem: normalized, formatted, country, type y valid. Cuando valid es false, leé el error — siempre es accionable. El mismo endpoint valida 1 o N.
$ curl -X POST https://api.normadata.io/v1/validate/tax-ids \
-H "X-API-Key: nd_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "id": "a", "value": "20-12345678-6", "country": "AR", "type": "cuit" },
{ "id": "b", "value": "123.456.789-09", "country": "BR" }
]
}'{
"results": [
{
"id": "a",
"country": "AR",
"type": "cuit",
"valid": true,
"normalized": "20123456786",
"formatted": "20-12345678-6"
},
{
"id": "b",
"country": "BR",
"type": "cpf",
"valid": true,
"normalized": "12345678909",
"formatted": "123.456.789-09"
}
]
}const res = await fetch("https://api.normadata.io/v1/validate/tax-ids", {
method: "POST",
headers: {
"X-API-Key": process.env.ND_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{ id: "a", value: "20-12345678-6", country: "AR", type: "cuit" },
{ id: "b", value: "123.456.789-09", country: "BR" },
],
}),
});
const { results } = await res.json();
// Same endpoint for 1 or N items — one result per item, by id.
for (const r of results) console.log(r.id, r.valid, r.normalized);import os
import requests
res = requests.post(
"https://api.normadata.io/v1/validate/tax-ids",
headers={
"X-API-Key": os.environ["ND_KEY"],
"Content-Type": "application/json",
},
json={
"items": [
{"id": "a", "value": "20-12345678-6", "country": "AR", "type": "cuit"},
{"id": "b", "value": "123.456.789-09", "country": "BR"},
],
},
)
# Same endpoint for 1 or N items — one result per item, by id.
for r in res.json()["results"]:
print(r["id"], r["valid"], r.get("normalized"))Cualquier cliente HTTP sirve
Todavía no shippeamos SDKs. La API es REST + JSON estricto, así que cURL, fetch, requests o net/http funcionan out of the box. Los ejemplos de abajo cubren los casos más comunes.
API keys
Mandá el header X-API-Key en cada request. Las keys empiezan con nd_ seguido de 30 chars base62 (33 chars en total). Nunca expongas tu key en código del cliente — usala solo desde un servidor, función o infra de confianza.
X-API-Key: nd_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5nd_ prefix (3 chars)
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx base62 random (30 chars)
──────────────────────────────
nd_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5 (33 chars total)Anatomía del payload
Cada endpoint de Validate acepta un shape plano. Los campos extra se ignoran. Si mandás algo inválido, recibís un 422 con los campos fallidos listados.
{
"items": [ // 1..1000 items (500 for /records)
{
"id": "a", // your correlation id, returned verbatim
"value": "20-12345678-6", // raw input
"country": "AR", // ISO 3166-1 alpha-2 (required)
"type": "cuit" // optional — deduced within the country
}
]
}- countrystring · ISO 3166-1 alpha-2Excepto IBAN / Domain — esos son estándares globales.
- typestring · enumVer cobertura · todos los tipos soportados.
- valuestring · raw inputEspacios, puntos y guiones permitidos — los limpiamos y canonicalizamos.
Tax IDs
Cuentas
Emails
Teléfonos
Records
Códigos posibles
HTTP estándar más códigos de warning del producto dentro de la respuesta. valid: false no es un error HTTP — devolvemos 200 con valid: false y una razón legible.
Cada respuesta incluye un header X-Request-Id, también devuelto en los bodies de error. Cuando reportes un problema a hello@normadata.io, incluilo — nos permite trazar la request exacta en nuestros logs.
| Status | Code | Significado |
|---|---|---|
| 200 | results[] | Lote procesado. Leé results[]: cada resultado trae su propio valid y un error cuando valid es false. |
| 400 | empty_batch | JSON mal formado o array items vacío. El code indica la causa (empty_batch, batch_too_large). |
| 401 | invalid_api_key | Header X-API-Key faltante o inválido. |
| 429 | quota_exceeded | Cuota mensual o rate por key excedido. Leé Retry-After en segundos. |
| 5xx | internal_error | Error inesperado del servidor. Reintentá en 5s con jitter. |
| 200 | valid: false | Estructura o dígito verificador inválido. El motivo viaja en el campo error de ese ítem; el resto del lote no se interrumpe. |
| 400 | empty_batch | El array items vino vacío. |
| 400 | batch_too_large | Más de 1.000 ítems (500 en /records). Paginá el lote. |
| 429 | quota_exceeded | El lote supera la cuota mensual restante. Leé Retry-After. |
Por key durante acceso anticipado
Los rate limits se configuran por API key durante acceso anticipado. Los números concretos van en la cuenta una vez que estés onboarded. La respuesta incluye los headers estándar X-RateLimit-* para que tu cliente pueda hacer back-off limpio.
X-RateLimit-Limit: 60000
X-RateLimit-Remaining: 55872
X-RateLimit-Reset: 2026-07-01T00:00:00Z
Retry-After: 1Los límites se negocian por workload. Si necesitás más burst o quota, mencionalo en el formulario de waitlist y lo seteamos antes de emitir tu key.
¿Tenés una pregunta puntual?
Email a hello@normadata.io — respondemos en 24h o antes.