CPFHub.io

Consulta de CNPJ por Lote

Envía una lista de hasta 10.000 CNPJ y recibe, para cada uno, el mismo registro de la Consulta de CNPJ, procesado en segundo plano. Cuesta 1 crédito por CNPJ encontrado.

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

Abrir en Cursor

Sin código, el dashboard acepta una lista de CNPJ y muestra el resultado de cada uno.

Flujo en dos pasos:

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

Endpoint

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

Parámetros

DóndeNombreObligatorioDescripción
Headerx-api-keySíTu API Key. Ver Autenticación.
HeaderContent-TypeSíapplication/json
BodycnpjsSístring[] de CNPJ, con o sin formato, numéricos o alfanuméricos. No vacío, máximo 10.000. Los elementos que no son string cuentan como inválidos.
BodyfileNameNoEtiqueta libre. Vuelve como file_name en el status.
BodyformatNoEtiqueta libre del formato de origen (ej.: "csv"). Vuelve como format.

Qué pasa en el envío

EtapaEfecto
NormalizaciónElimina puntos, barra y guion y convierte las letras a mayúsculas. Los CNPJ con formato o dígito verificador incorrecto van a invalid y no se cobran.
DuplicadosSe eliminan. Cada CNPJ se consulta y se cobra una vez. No cuentan en totalRecords ni en invalid.
SaldoSin excedente, el saldo debe cubrir todos los CNPJ válidos (totalRecords × costo de la consulta, 1 crédito por defecto). Si no alcanza, 403 y no se cobra nada.
Lotes pendientesHay un límite de lotes en procesamiento al mismo tiempo por cliente. Por encima de él, 429.

Más de 10.000 CNPJ: divídelos en bloques y envía un POST por cada uno, esperando a los anteriores si recibes 429.

Ejemplo

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

curl -X POST "https://api.cpfhub.io/cnpj/bulk" \
  -H "x-api-key: $CPFHUB_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "cnpjs": ["11222333000181", "12.ABC.345/01DE-35"]
  }'

Respuesta

HTTP 202 Accepted

JSON
{
  "success": true,
  "data": {
    "jobId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "status": "processing",
    "totalRecords": 2,
    "invalid": 0
  }
}
CampoTipoDescripción
data.jobIdstringID del lote. Guárdalo para consultar el status.
data.statusstringSiempre "processing"
data.totalRecordsnumberCNPJ válidos y únicos que se consultarán
data.invalidnumberElementos descartados (formato, dígito verificador o no string)

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

Status y resultados

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

Usa la misma API Key del envío. No consume crédito y funciona con saldo cero.

Polling:

  • Empieza cada 5 s y aumenta hasta 30 s en lotes grandes. Cada llamada devuelve el array cnpjs completo, y cada registro de CNPJ es bastante mayor que el de un CPF.
  • Define un plazo máximo en el cliente (ej.: 30 min). El tiempo del lote depende de cuántos CNPJ hay en el envío.
  • Ante 5xx o un error de red, vuelve a intentar en el siguiente ciclo. El GET es seguro de repetir.
curl "https://api.cpfhub.io/cnpj/bulk/7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -H "x-api-key: $CPFHUB_API_KEY"

HTTP 200 OK

JSON
{
  "success": true,
  "data": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "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-15T14:15:16.000Z",
    "updated_at": "2026-10-15T14:15:18.000Z",
    "cnpjs": [
      {
        "cnpj": "11222333000181",
        "found": true,
        "data": {
          "cnpj": "11222333000181",
          "razao_social": "EMPRESA EXEMPLO LTDA",
          "situacao_cadastral": "Ativa",
          "...": "demás campos de la Consulta de CNPJ"
        }
      },
      {
        "cnpj": "12ABC34501DE35",
        "found": false,
        "data": null
      }
    ]
  }
}
CampoDescripción
data.idID del lote (el jobId del envío)
data.status"processing", "done" o "failed"
data.total_recordsCNPJ válidos y únicos en el lote
data.processedCNPJ ya procesados (incluye skipped)
data.foundEncontrados. Cada uno consume 1 crédito por defecto (costo de tu plan 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.cnpjs[]Resultado de cada CNPJ procesado: cnpj (14 caracteres sin formato), found y data, que es el mismo registro de la Consulta de CNPJ o null cuando found es false

Durante "processing", los contadores se actualizan por intervalos y pueden ir por detrás de cnpjs.

Errores

La API responde solo en portugués. Los mensajes de error aparecen tal como llegan.

StatusCuándo ocurreQué hacer
400cnpjs ausente, vacío, no es array ("Campo 'cnpjs' deve ser um array não vazio.") o tiene más de 10.000 elementos ("Limite de 10000 CNPJs por lote excedido.")Corrige el body.
401API Key ausente, inválida o inactiva (error string)Revisa el header x-api-key.
403Sin excedente: saldo menor que el lote (error.message: "Créditos insuficientes para o lote: N necessários.", créditos insuficientes). También saldo cero y cuenta inactiva/bloqueada. Solo en el POST.Recarga créditos o reduce el lote.
404El jobId no existe o se creó con otra API Key ("Lote não encontrado.")Revisa el jobId y la clave.
422Ningún CNPJ válido en la lista ("Nenhum CNPJ válido na lista enviada.")Corrige la lista.
429Límite por minuto superado, o límite de lotes pendientes ("Limite de N lotes pendentes por cliente excedido."). Solo en el POST.Espera los segundos del header Retry-After (60 s en el límite de lotes pendientes). Deja que terminen los lotes anteriores antes de enviar otros.
500"Falha ao criar lote." (no se pudo crear el lote). No se creó ningún lote.Vuelve a intentar. Repórtalo si persiste.

Formato del error y reintentos: 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. cnpjs ya trae resultados parciales.
Completado"done" y skipped: 0Usa cnpjs.
Completado con omitidos"done" y skipped > 0El saldo se agotó durante el lote. Recarga y reenvía solo los CNPJ que faltaron.
Falló"failed"Lee error. Los encontrados en cnpjs ya se cobraron. Reenvía solo los que faltaron.

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

Cruzar los resultados con tu lista

cnpjs no sigue el orden del envío y no incluye skipped ni los no procesados. Normaliza tu lista (sin puntos, barra ni guion, en mayúsculas) y cruza por el campo cnpj. Los que falten son los que debes reenviar (incluye los inválidos, que no cuestan nada).

const normalize = (cnpj: string) => cnpj.replace(/[./-]/g, '').toUpperCase()

const results = new Map(job.cnpjs.map((item) => [item.cnpj, item]))

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

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

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. Con respuesta de error, no se creó ningún lote.
  • Crédito: solo se cobra found: true, al mismo costo y de la misma franquicia que la Consulta Simple de CPF. Inválidos, repetidos, no encontrados y skipped no se cobran.
  • Fuente de los datos: la misma de la Consulta de CNPJ: base pública mensual de la Receita Federal, procesada por OpenCNPJ. Los datos pueden estar desactualizados hasta la próxima actualización mensual.
  • Datos de ejemplo: los CNPJ y los datos anteriores son ficticios.

Actualizado el 15 de octubre de 2026