CPFHub.io

Consulta por Lote

Envía una lista de hasta 10.000 CPF (el número de identificación fiscal de personas físicas en Brasil) y recibe, para cada uno, el nombre, el género y la fecha de nacimiento, procesados en segundo plano. Cuesta 1 crédito por CPF encontrado.

¿Usas Cursor, Lovable, v0 u otra IA? Copia el prompt de la consulta por lote y pégalo en tu asistente.

Abrir en Cursor

¿No es esta? Compara las consultas. Si prefieres no escribir código, el dashboard acepta archivos CSV/TXT o CPF pegados y exporta el resultado en CSV.

Flujo en dos pasos:

  1. POST /cpf/bulk envía la lista y responde de inmediato con un jobId.
  2. GET /cpf/bulk/{jobId} devuelve el progreso y los resultados. Repite hasta que status sea "done" o "failed".

Endpoint

POSThttps://api.cpfhub.io/cpf/bulk

Parámetros

DóndeNombreObligatorioDescripción
Headerx-api-keySíTu clave de API. Consulta Autenticación.
HeaderContent-TypeSíapplication/json
BodycpfsSístring[] de CPF, con o sin formato. No vacío, máximo 10.000. Los elementos que no son cadenas cuentan como inválidos.
BodyfileNameNoEtiqueta libre. Vuelve como file_name en el estado.
BodyformatNoEtiqueta libre del formato de origen (por ejemplo, "csv"). Vuelve como format.

Qué pasa al enviar

EtapaEfecto
NormalizaciónQuita el formato. Los CPF sin 11 dígitos o con dígito verificador incorrecto van a invalid y no se cobran.
DuplicadosSe eliminan. Cada CPF se consulta y se cobra una sola vez. No cuentan en totalRecords ni en invalid.
Límite por minutoCada envío cuenta como una solicitud en el límite de la Consulta Simple (30 por minuto por defecto).
SaldoSin excedente: el saldo debe cubrir todos los CPF válidos (totalRecords × el costo de la Consulta Simple, 1 crédito por defecto). Si no alcanza, recibes 403 y no se cobra nada.

Más de 10.000 CPF: divídelos en bloques y envía un POST por cada uno.

Ejemplo

Revisa el estado antes de leer data: en caso de error, la respuesta no trae jobId.

curl -X POST "https://api.cpfhub.io/cpf/bulk" \
  -H "x-api-key: $CPFHUB_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "cpfs": ["12345678909", "11144477735", "52998224725"]
  }'

Respuesta

HTTP 202 Accepted

JSON
{
  "success": true,
  "data": {
    "jobId": "4a1ef25e-052c-4464-9657-4148f53bb0fc",
    "status": "processing",
    "totalRecords": 3,
    "invalid": 0
  }
}
CampoTipoDescripción
data.jobIdstringID del lote. Guárdalo para consultar el estado.
data.statusstringSiempre "processing"
data.totalRecordsnumberCPF válidos y únicos que se van a consultar
data.invalidnumberElementos descartados (formato, dígito verificador o no es una cadena)

El envío responde en camelCase. El estado responde en snake_case.

Estado y resultados

GEThttps://api.cpfhub.io/cpf/bulk/{jobId}

Usa la misma clave de API del envío. No consume crédito, no cuenta en el límite por minuto y funciona con saldo en cero.

Polling:

  • Empieza cada 5 s y aumenta hasta 30 s en lotes grandes. Cada llamada devuelve el array cpfs completo (hasta ~2 MB con 10.000 CPF).
  • Define un plazo máximo en el cliente (por ejemplo, 30 min). El tiempo del lote depende de cuántos CPF envíes, y cada consulta queda en el mismo rango de la Consulta Simple (~150 ms).
  • Ante un 5xx o un error de red, reintenta en el siguiente ciclo. Es seguro repetir el GET.
curl "https://api.cpfhub.io/cpf/bulk/4a1ef25e-052c-4464-9657-4148f53bb0fc" \
  -H "x-api-key: $CPFHUB_API_KEY"

HTTP 200 OK

JSON
{
  "success": true,
  "data": {
    "id": "4a1ef25e-052c-4464-9657-4148f53bb0fc",
    "status": "done",
    "file_name": null,
    "format": null,
    "total_records": 2,
    "processed": 2,
    "found": 1,
    "not_found": 1,
    "skipped": 0,
    "error": null,
    "created_at": "2026-10-02T14:15:16.000Z",
    "updated_at": "2026-10-02T14:15:18.000Z",
    "cpfs": [
      {
        "cpf": "12345678909",
        "found": true,
        "name": "Fulano de Tal",
        "nameUpper": "FULANO DE TAL",
        "gender": "M",
        "birthDate": "15/06/1990",
        "day": 15,
        "month": 6,
        "year": 1990
      },
      {
        "cpf": "52998224725",
        "found": false,
        "name": null,
        "nameUpper": null,
        "gender": null,
        "birthDate": null,
        "day": null,
        "month": null,
        "year": null
      }
    ]
  }
}
CampoDescripción
data.idID del lote (el jobId del envío)
data.status"processing", "done" o "failed"
data.total_recordsCPF válidos y únicos en el lote
data.processedCPF ya procesados (incluye skipped)
data.foundEncontrados. Cada uno consume 1 crédito por defecto (el costo de tu plan está en el dashboard)
data.not_foundNo encontrados. No consumen crédito.
data.skippedNo consultados porque el saldo se agotó durante el lote (sin excedente). No consumen crédito.
data.errorMotivo de la falla cuando status es "failed"
data.file_name, data.formatEtiquetas enviadas en el POST
data.created_at, data.updated_atFechas ISO 8601
data.cpfs[]Resultado de cada CPF procesado: cpf (11 dígitos), found, name, nameUpper, gender, birthDate, day, month, year (null cuando found es false)

Mientras el estado es "processing", los contadores se actualizan cada 50 CPF y pueden ir por detrás de cpfs.

Errores

La API responde solo en portugués. Los mensajes de error se muestran tal como llegan, con la traducción entre paréntesis la primera vez.

EstadoCuándo ocurreQué hacer
400cpfs ausente, vacío, no es un array o tiene más de 10.000 elementosCorrige el body.
401Clave de API ausente, inválida o inactiva (error es una cadena)Revisa el header x-api-key.
403Sin excedente: saldo en cero (error cadena "Limite de créditos excedido", límite de créditos excedido) o saldo menor que el lote (error.message: "Créditos insuficientes para o lote: N necessários.", créditos insuficientes para el lote: se necesitan N). También cuenta inactiva/bloqueada. Solo en el POST.Recarga créditos o reduce el lote.
404El jobId no existe o se creó con otra clave de APIRevisa el jobId y la clave.
422Ningún CPF válido en la listaCorrige la lista.
429Límite por minuto excedido (solo en el POST)Espera los segundos indicados en el header Retry-After.
500, 503Falla pasajera. No se creó ningún lote.Intenta de nuevo. Repórtalo si persiste.

Formato del error, reintentos y cómo probar sin gastar créditos: Códigos de Error. Límite por minuto y créditos: Límites de Uso.

Detalles

Estados del lote

SituaciónCómo identificarlaQué hacer
En procesamientostatus: "processing"Sigue con el polling. cpfs ya trae resultados parciales.
Completado"done" y skipped: 0Usa cpfs.
Completado con omitidos"done" y skipped > 0El saldo se agotó durante el lote. Recarga y reenvía solo los CPF que faltaron.
Falló"failed"Lee error. Los encontrados en cpfs ya fueron cobrados. Reenvía solo los que faltaron.

Valores de error cuando el lote falla:

errorSignificado
"Banco de dados indisponível" (base de datos no disponible)No se procesó ni se cobró nada.
"Falha ao registrar validação" (falla al registrar la consulta)Falló al guardar un resultado. El procesamiento se detuvo.
"Worker interrompido (job órfão)" (worker interrumpido, job huérfano)El procesamiento se interrumpió. Se marca así tras ~10 min sin actualización.

Con excedente, ningún CPF se omite: todos se consultan y el excedente se cobra.

Cruzar los resultados con tu lista

cpfs llega en orden de procesamiento y no incluye los skipped ni los no procesados. Normaliza tu lista a 11 dígitos y cruza por el campo cpf. Los que falten son los que debes reenviar (incluye los inválidos, que no cuestan nada).

const normalize = (cpf: string) => cpf.replace(/\D/g, '')

const results = new Map(job.cpfs.map((item) => [item.cpf, item]))

for (const original of myCpfs) {
  const result = results.get(normalize(original))
  console.log(original, result ? (result.found ? result.name : 'no encontrado') : 'sin resultado')
}

// CPF para reenviar en un nuevo lote (si el lote falló o tuvo skipped)
const missing = [...new Set(myCpfs.map(normalize))].filter((cpf) => !results.has(cpf))

Más

  • Envío no idempotente: cada POST aceptado crea un lote nuevo y cobra los encontrados. Si la conexión se cae sin jobId, revisa el dashboard o GET /quota antes de reenviar. Si recibiste una respuesta de error, no se creó ningún lote.
  • Crédito: solo se cobra found: true. Los inválidos, repetidos, no encontrados y skipped no se cobran.
  • Exportación CSV: solo en el dashboard, con las columnas CPF, Nome (nombre), Nascimento (fecha de nacimiento) y Encontrado (encontrado), sin género.

Actualizado el 4 de octubre de 2026