Códigos de Error
La API sigue las convenciones REST estándar para los códigos de estado HTTP. Usa el estado HTTP para decidir qué hacer y el mensaje solo para logs o para mostrarlo.
Estructura de un error
Hay dos formatos. La mayoría de los errores traen error como objeto con message:
{
"success": false,
"data": null,
"error": {
"message": "CPF não encontrado na base de dados"
}
}Los errores de autenticación y de cuenta traen error como cadena: 401, 403 de cuenta inactiva o bloqueada, 403 "Limite de créditos excedido" (límite de créditos excedido) en el envío de lote con saldo en cero, 500 "Erro ao validar assinatura" (error al validar la suscripción) y 503 "usage_unavailable". El 403 de créditos en la Consulta Simple y en la Consulta en Tiempo Real viene como objeto.
{
"success": false,
"error": "API Key não fornecida"
}Para leer el mensaje en ambos casos: typeof body.error === 'string' ? body.error : body.error?.message.
Usa el estado HTTP
Decide el manejo según el estado HTTP. Los mensajes están en portugués y sirven para logs y para mostrarlos, así que no compares el texto en tu código. Las traducciones entre paréntesis de abajo son solo de referencia.
Referencia completa
2xx: Éxito
| Estado | Mensaje | Descripción |
|---|---|---|
200 OK | Ninguno | Consulta exitosa. El campo data contiene los resultados. |
202 Accepted | Ninguno | Solo en la consulta por lote: lote aceptado para procesamiento. |
4xx: Errores del cliente
| Estado | Mensaje | Descripción |
|---|---|---|
400 Bad Request | CPF inválido. Deve conter 11 dígitos. (el CPF debe tener 11 dígitos) | El CPF no tiene 11 dígitos después de quitar el formato. |
400 Bad Request | Data de nascimento inválida. Use o formato DD/MM/YYYY ou DDMMYYYY (fecha de nacimiento incorrecta, usa el formato DD/MM/YYYY o DDMMYYYY) | Solo en la Consulta en Tiempo Real: birthDate ausente o inválido. |
400 Bad Request | Campo 'cpfs' deve ser um array não vazio. (el campo cpfs debe ser un array no vacío) | Solo en la consulta por lote: cpfs ausente, vacío o no es un array. |
400 Bad Request | Limite de 10000 CPFs por lote excedido. (límite de 10.000 CPF por lote excedido) | Solo en la consulta por lote: más de 10.000 CPF. |
401 Unauthorized | API Key não fornecida (clave de API no enviada) | Falta el header x-api-key. error es una cadena. |
401 Unauthorized | API Key inválida (clave de API inválida) | La clave de API no existe. error es una cadena. |
401 Unauthorized | API Key inativa (clave de API inactiva) | La clave de API fue reemplazada por una nueva en el dashboard. error es una cadena. |
403 Forbidden | Limite de créditos excedido (límite de créditos excedido) | Saldo menor que el costo de la consulta, en planes sin excedente. En la Consulta Simple y en la Consulta en Tiempo Real, error es un objeto. En el envío de lote con saldo insuficiente para una sola consulta, error es una cadena. |
403 Forbidden | Créditos insuficientes para o lote: N necessários. (créditos insuficientes para el lote: se necesitan N) | Solo en la consulta por lote: el saldo no cubre todos los CPF válidos de la lista, en planes sin excedente. |
403 Forbidden | Usuário inativo. Entre em contato com o suporte. (usuario inactivo, contacta a soporte) | Cuenta desactivada. error es una cadena. |
403 Forbidden | Conta bloqueada. Entre em contato com o suporte. (cuenta bloqueada, contacta a soporte) | Cuenta bloqueada. error es una cadena. |
404 Not Found | CPF não encontrado na base de dados (CPF no encontrado en la base de datos) | Solo en la Consulta Simple. No consume crédito. |
404 Not Found | Lote não encontrado. (lote no encontrado) | Solo en el estado del lote: el jobId no existe o se creó con otra clave de API. En raros casos de falla interna también aparece, así que repite una vez antes de tratar el lote como inexistente. |
422 Unprocessable Entity | CPF inválido. Dígito verificador incorreto. (dígito verificador incorrecto) | El CPF falló la validación matemática de los dígitos verificadores. |
422 Unprocessable Entity | Nenhum CPF válido na lista enviada. (ningún CPF válido en la lista enviada) | Solo en la consulta por lote: ningún elemento de la lista es un CPF válido. |
422 Unprocessable Entity | Mensaje de la Receita Federal | Solo en la Consulta en Tiempo Real: la Receita rechazó la consulta, por ejemplo porque la fecha de nacimiento no coincide. No consume crédito. |
429 Too Many Requests | Limite de requisições por minuto excedido. Tente novamente em N segundos. (límite de solicitudes por minuto excedido, intenta de nuevo en N segundos) | Superaste el límite por minuto de la Consulta Simple, de la Consulta en Tiempo Real o del envío de lote. Trae el header Retry-After. No consume crédito. |
Una ruta que no existe responde 404 con el texto plano NOT_FOUND, sin JSON. Revisa el Content-Type antes de leer el cuerpo como JSON.
5xx: Errores del servidor
| Estado | Mensaje | Descripción |
|---|---|---|
500 Internal Server Error | Erro ao validar assinatura (error al validar la suscripción) | Falla interna al leer tu plan. error es una cadena. |
500 Internal Server Error | Banco de dados indisponível (base de datos no disponible) | Falla interna en la Consulta Simple. |
500 Internal Server Error | Falha ao criar lote. (falla al crear el lote) | Solo en la consulta por lote: no se pudo crear el lote. |
502 Bad Gateway | Falha ao interpretar a resposta da Receita Federal. (falla al interpretar la respuesta de la Receita Federal) | Solo en la Consulta en Tiempo Real. No consume crédito. |
502 / 503 | A Receita Federal não respondeu a tempo. Tente novamente em alguns segundos. Nenhum crédito foi cobrado. (la Receita Federal no respondió a tiempo, intenta de nuevo en unos segundos, no se cobró ningún crédito) | Solo en la Consulta en Tiempo Real. No consume crédito. |
502 / 503 | A Receita Federal está com alta demanda agora. Tente novamente em alguns segundos. Nenhum crédito foi cobrado. (la Receita Federal tiene alta demanda ahora, intenta de nuevo en unos segundos, no se cobró ningún crédito) | Solo en la Consulta en Tiempo Real. No consume crédito. |
503 Service Unavailable | Não foi possível reservar os créditos. Tente novamente. (no fue posible reservar los créditos, intenta de nuevo) | Falla interna al reservar los créditos de la consulta. No consume crédito. |
503 Service Unavailable | Falha ao registrar validação (falla al registrar la consulta) | Falla interna al guardar la consulta. No consume crédito. |
503 Service Unavailable | usage_unavailable | No fue posible verificar el saldo de créditos. No consume crédito. |
El 503 de saldo no disponible trae error como cadena y un campo message:
{
"success": false,
"error": "usage_unavailable",
"message": "Não foi possível verificar o saldo de créditos. Tente novamente."
}Ejemplo de manejo de errores
const res = await fetch(`https://api.cpfhub.io/cpf/${cpf}`, {
headers: { 'x-api-key': process.env.CPFHUB_API_KEY! },
signal: AbortSignal.timeout(10_000),
})
const isJson = res.headers.get('content-type')?.includes('application/json')
const body = isJson ? await res.json() : null
if (res.ok) {
console.log(body.data.name)
} else {
// error es cadena en algunos errores y objeto { message } en los demás
const message = typeof body?.error === 'string' ? body.error : body?.error?.message
switch (res.status) {
case 404:
// CPF no encontrado: no consume crédito
break
case 400:
case 422:
// Entrada incorrecta: corrígela, no repitas
break
case 401:
case 403:
// Clave incorrecta, créditos agotados o cuenta bloqueada: no repitas
throw new Error(message)
case 429:
// Límite por minuto: espera Retry-After segundos y repite
await new Promise(r => setTimeout(r, Number(res.headers.get('retry-after') ?? 5) * 1000))
break
default:
// 5xx: repite con backoff (ver la tabla de abajo)
throw new Error(message ?? `HTTP ${res.status}`)
}
}import os, time, requests
res = requests.get(
f"https://api.cpfhub.io/cpf/{cpf}",
headers={"x-api-key": os.environ["CPFHUB_API_KEY"]},
timeout=10,
)
is_json = "application/json" in res.headers.get("content-type", "")
body = res.json() if is_json else {}
if res.ok:
print(body["data"]["name"])
else:
error = body.get("error")
message = error if isinstance(error, str) else (error or {}).get("message")
if res.status_code == 404:
print("CPF no encontrado")
elif res.status_code == 429:
time.sleep(int(res.headers.get("retry-after", "5"))) # luego repite
elif res.status_code >= 500:
pass # repite con backoff
else:
raise RuntimeError(message)Reintentos
| Estado | ¿Repetir? | Cómo |
|---|---|---|
429 | Sí | Espera el valor del header Retry-After |
500, 502, 503 en un GET (Consulta Simple, estado del lote, saldo) | Sí, hasta 3 veces | Backoff: 1 s, 2 s, 4 s |
502, 503 recibidos en POST /cpf/realtime | Sí, hasta 3 veces | Backoff: 2 s, 4 s, 8 s |
400, 401, 403, 404, 422 | No | Corrige la entrada, la clave o el saldo |
POST no es idempotente
POST /cpf/realtime y POST /cpf/bulk no aceptan clave de idempotencia. Si la conexión se cae o tu timeout se agota antes de la respuesta, la consulta pudo completarse y cobrarse, o el lote pudo haberse creado. Antes de repetir, revisa el saldo en GET /quota y, en el lote, los envíos recientes en el dashboard. Repite sin revisar solo cuando hayas recibido 429, 502 o 503.
Probar sin gastar créditos
No consumen crédito: 400, 401, 404, 422 y 429. Puedes probar el manejo de errores gratis:
| Prueba | Solicitud | Respuesta |
|---|---|---|
| CPF con menos de 11 dígitos | GET /cpf/123 | 400 |
| Dígito verificador incorrecto | GET /cpf/11111111111 | 422 |
| Fecha de nacimiento inválida | POST /cpf/realtime con {"cpf":"12345678909","birthDate":"1990-06"} | 400 |
| Sin clave de API | cualquier ruta, sin el header x-api-key | 401 |
| Saldo de la cuenta | GET /quota | 200, siempre gratis |
- Una respuesta
200consume crédito. El plan Gratis tiene 50 créditos para probar el camino de éxito. - El CPF
12345678909de los ejemplos es ficticio. Para probar el éxito, usa un CPF cuyo titular haya autorizado la consulta.
Actualizado el 4 de octubre de 2026