# CNPJ Lookup — Consulta CNPJ Receita Federal (Brazil) (`publicdata/cnpj-lookup-receita-federal`) Actor

Brazil CNPJ lookup and company data from Receita Federal open data: legal name, trade name, registration status, CNAE activities, legal nature, share capital, size, address, contacts and the full list of partners. Batch input, two official mirrors with automatic failover.

- **URL**: https://apify.com/publicdata/cnpj-lookup-receita-federal.md
- **Developed by:** [PublicData](https://apify.com/publicdata) (community)
- **Categories:** Lead generation, Other
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.25 / 1,000 companies

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

**Paste a column of CNPJ numbers and get back a finished table of Brazilian company records — legal name, registration status, CNAE activity, location and partners — instead of running a manual consulta CNPJ one company at a time.**

Sales lists, supplier files and KYC queues in Brazil arrive the same way: a spreadsheet with a CNPJ column and little else. This Actor turns that column into brazil company data you can sort and filter. It reads the Receita Federal open dataset through two independent public mirrors and returns one row for every CNPJ you submit — including the ones that fail.

#### Why this and not a raw free endpoint

Free keyless CNPJ endpoints exist, and this Actor calls them. What you pay for is the operational layer around them, which is what breaks on a 5,000-line bulk CNPJ job:

- **Failover to a genuinely separate mirror.** Every lookup tries `minhareceita.org` first and falls back to **OpenCNPJ** — a different project, on different infrastructure, built from the same Receita Federal extract. One provider having a bad afternoon does not end your run. `BrasilAPI` is tried last and only as a cache: its CNPJ route is a one-line HTTP proxy in front of minhareceita, so it is not an independent source and cannot answer once that origin is truly down.
- **Local check-digit validation.** Both check digits are verified before a request is spent, so typos and truncated cells cost nothing.
- **One row in, one row out.** An unresolvable CNPJ still produces a row carrying a `lookupError` field, so your input maps 1:1 to the output.
- **Batch paste.** A whole spreadsheet column into one field, with or without punctuation.

### What you get

**Identity** — **`cnpj`** (formatted) and **`cnpjRaw`** (14 digits, for joining back to your table), **`legalName`** (razão social), `tradeName` (nome fantasia), `isHeadOffice` for matriz versus filial.

**Standing** — **`status`**: ATIVA, BAIXADA, SUSPENSA, INAPTA or NULA, with `statusReason`, `statusDate` and `startDate`.

**Activity and legal form** — **`mainActivity`** and **`mainActivityCode`** (the primary **CNAE**), `secondaryActivities` with code and description, `legalNature` and `legalNatureCode` (natureza jurídica).

**Size and tax regime** — **`shareCapital`** in BRL, `companySize` — the Receita Federal *porte* band verbatim, one of exactly three strings: `MICRO EMPRESA`, `EMPRESA DE PEQUENO PORTE` or `DEMAIS` (250 of 250 companies in a live sample drawn 2026-08-21 carried one of the three, and both mirrors spell them identically) — plus `isSimplesOptant` and `isMEI`.

**Location and contact** — `district`, `city`, `state` and `postalCode` on every resolved row, plus `phone` and `email`. Contacts come from the OpenCNPJ mirror, the only one of the three that publishes the e-mail: in a random sample of 205 live companies drawn on 2026-08-21, 182 had a phone (89%) and 149 an e-mail (73%). `address` — the street line — is the thin one: the primary mirror returns it blank for most of the register, so it was filled on 76 of those 205 rows (37%). The rest still carry `district`, `city`, `state` and `postalCode`.

**People** — **`partners`**, the quadro societário: name, role, entry date, age band, country and legal representative for each partner or officer.

**Provenance** — `source`, `sourceUrl`, `lookupError`.

### Who uses this

- **Sales and RevOps** — a lead list arrives as CNPJs only; you need legal name, city, CNAE and size before routing it.
- **Compliance and KYC analysts** — confirm a counterparty is ATIVA, read the quadro societario, record the Simples/MEI regime, keep the source link on file.
- **Procurement and supplier onboarding** — check a vendor's head-office flag, activity start date and registered city, state and CEP before the first purchase order.
- **Credit and finance analysts** — pull share capital, legal nature and status across a whole portfolio in one run.
- **Developers and AI agents** — a brazilian company lookup behind a normal API call, or an MCP tool an agent invokes mid-conversation.

### Example output

One row per CNPJ, shortened. Partner names are returned in full, redacted here.

```json
{
  "cnpj": "19.131.243/0001-97",
  "cnpjRaw": "19131243000197",
  "legalName": "OPEN KNOWLEDGE BRASIL",
  "tradeName": "REDE PELO CONHECIMENTO LIVRE",
  "status": "ATIVA",
  "isHeadOffice": true,
  "startDate": "2013-10-03",
  "legalNature": "Associação Privada",
  "mainActivity": "Atividades de associações de defesa de direitos sociais",
  "shareCapital": 0,
  "companySize": "DEMAIS",
  "city": "SAO PAULO",
  "state": "SP",
  "partners": [
    { "name": "…", "role": "Presidente", "since": "…", "ageBand": "…", "country": null }
  ],
  "source": "Receita Federal open data (minhareceita.org / OpenCNPJ mirrors)"
}
```

A number that cannot be resolved still comes back, so the row count never changes:

```json
{
  "cnpj": "11.111.111/1111-11",
  "cnpjRaw": "11111111111111",
  "legalName": null,
  "lookupError": "invalid CNPJ check digits",
  "source": "Receita Federal open data (minhareceita.org / OpenCNPJ mirrors)"
}
```

`lookupError` is a closed vocabulary — the Actor emits these five strings and no others, so you can filter on them:

| `lookupError` | What happened |
|---|---|
| `not a 14-digit CNPJ` | The cell did not contain 14 digits. No request was spent. |
| `invalid CNPJ check digits` | 14 digits, but the two check digits do not verify. No request was spent. |
| `CNPJ not found in the Receita Federal register` | Both mirrors answered, neither knows this number. |
| `no source mirror could be reached` | Every mirror was unreachable for this row — an upstream outage, not a problem with your input. |
| `unexpected response from the source mirrors` | A mirror answered, but with a body that is not a company record. |

Reproduced on 2026-08-21: the first three live against the real mirrors, `no source mirror could be reached` against both origins blackholed, `unexpected response from the source mirrors` in the test suite.

### Input

| Field | What it is |
|---|---|
| `cnpjList` | CNPJ numbers as a list, punctuation optional. Head offices end in 0001-XX. |
| `cnpjText` | Or paste many at once — commas, spaces or new lines, straight from a spreadsheet. |
| `includePartners` | Include the quadro societário. Default `true`. |
| `includeContacts` | Include the registered phone and e-mail. Costs one extra lookup per company, because the primary mirror strips the e-mail; turn it off to halve the requests. Default `true`. |
| `skipInactive` | Drop companies whose status is not ATIVA. Default `false`. |
| `maxItems` | Cap on rows exported. `0` = unlimited. The run reads further down your list to replace companies dropped by `skipInactive`, so the cap is a target, never a truncation of your input. |

Duplicates are collapsed, so a messy column is safe to paste.

Company-level data only, no personal data at all:

```json
{
  "cnpjText": "33.000.167/0001-01\n00.000.000/0001-91\n19131243000197",
  "includePartners": false,
  "includeContacts": false
}
```

A KYC-style run: full partner list, active companies only.

```json
{
  "cnpjList": ["19.131.243/0001-97", "33000167000101"],
  "includePartners": true,
  "skipInactive": true
}
```

### Run it on a schedule

Save your CNPJ list as a task and give it an Apify schedule — daily, weekly, or monthly to match the register's refresh. Each run re-checks the same companies, so a supplier going BAIXADA or a change in the quadro societário shows up in the next output on its own.

Apify integrations then push results out: **Google Sheets**, **Slack**, **e-mail**, a plain **webhook**, or **Make** and **Zapier** for CRM records, Airtable and ticket queues.

Use **`cnpjRaw`** as the deduplication key: the bare 14-digit number, stable across runs and the key most CRMs already store, so repeat runs update rows instead of stacking duplicates.

### Use it from code or from an AI agent

Start a run and read the dataset through the Apify API or CLI, from Python, Node.js or plain HTTP — the same CNPJ API call whether you run it once or nightly. Output comes as JSON, CSV, Excel or XML.

The Actor is also exposed as an **MCP tool** via the Apify MCP server, so an AI agent can look up a Brazilian company mid-conversation: pass a CNPJ, get the structured record, no scraping code on your side.

### Pricing

Pay per event: a small fixed charge per company row exported, **including rows that carry only a `lookupError`**. Companies dropped by `skipInactive` are never charged, and a run that exports no rows is charged nothing. No monthly rental. Platform usage on top is negligible — plain API calls, no browser. `maxItems` is a hard ceiling: the run stops the moment that many rows have been exported.

**What an upstream outage costs you.** The Actor has no circuit breaker. If every mirror is down it still returns one row per CNPJ — that is the 1:1 guarantee above — and every one of those rows is charged even though it carries no company data. Simulated live on 2026-08-21 with both origins blackholed: 20 CNPJs in, 20 rows exported, 20 rows charged, 0 rows with a `legalName`, all reading `no source mirror could be reached`. `skipInactive` does not protect you here, because a row with no `status` cannot be judged inactive: the same run with `skipInactive: true` still charged 20 of 20. On a 5,000-line list that is 5,000 charged empty rows. Set `maxItems`, or trial a handful of CNPJs first, if you suspect the mirrors are having a bad day.

### Where the data comes from

All data originates from the **Receita Federal do Brasil** public CNPJ register, published as **open data**. It is read through [minhareceita.org](https://minhareceita.org) (Open Knowledge Brasil) first, then [OpenCNPJ](https://opencnpj.org) — a separate project publishing its own build of the same official extract, which is what makes the failover real. [BrasilAPI](https://brasilapi.com.br) sits last in the chain for its edge cache only; its CNPJ endpoint proxies minhareceita, so it is a third door onto the first source rather than a third source. Every resolved row carries the official Receita Federal lookup page in `sourceUrl`.

Honest limits, all figures measured live on 2026-08-21 against a random sample of 205 companies drawn from the CNPJ base-number space. This is a periodic snapshot, not a live feed: the mirrors refresh when Receita Federal publishes a new extract, so a company registered or closed this week may not appear yet, and the two mirrors can be a few days apart. The register holds no revenue figures, balance sheets, credit scores, litigation records or shareholding percentages.

**Fields that are often empty.** `phone` was present on 182 of the 205 rows and `email` on 149. `secondaryActivities` was present on 109 — it is empty for companies that declared none. `address` was present on only 76 of the 205 (37%): the primary mirror returns the street type, street name and street number as empty strings for most of the register, for micro-entrepreneurs and ordinary companies alike (55 MEIs and 74 non-MEIs among the 129 blanks), while still returning `district`, `city`, `state` and `postalCode`. OpenCNPJ does publish a street for all 129 of those companies, but the Actor does not stitch one source's address onto the other's row — a row comes from one mirror or the other, whole. If the street line matters to you, treat `address` as best-effort and key on `postalCode` plus `district`.

Three fields are emptier still, and none of them was disclosed before. Measured on a **second, independent live sample of 250 companies** drawn from the same base-number space on 2026-08-21:

- **`partners` was present on 80 of the 250 rows (32%).** Reading the quadro societário is listed above as a KYC use case, so this is the number to plan around: on roughly two rows in three the register publishes no partner at all and `partners` is `null`. Of the 170 rows with no partners, 51 were MEIs, 74 were not, and 45 do not say.
- **`isSimplesOptant` and `isMEI` were both null on 73 of the 250 rows (29%)** — the same 73 rows on both fields, and genuinely blank at the source: all 73 came back blank from OpenCNPJ too. A null there means the register does not state the regime, not that the answer is no.
- **`tradeName` was present on 103 of the 250 rows (41%).** Companies that trade under their razão social simply have no nome fantasia.

For reference, the same 250-company sample put `secondaryActivities` at 132 (53%) and `address` at 104 (42%), consistent with the 205-company figures above; `district`, `city` and `state` were filled on 250 of 250 and `postalCode` on 249.

**`shareCapital` precision.** minhareceita serialises `capital_social` as a 32-bit float, so on the normal path `shareCapital` keeps only about seven significant digits: for 20 large companies checked live, the primary value was exactly the shortest decimal that round-trips through a 32-bit float in 20 of 20 cases. That is invisible for ordinary capital figures — 0 of the 205 sampled companies were affected — but it rounds large ones: 15 of the 20 differed from OpenCNPJ, by 0.78 BRL up to 2,134.91 BRL (02.558.157/0001-62: 56,071,418,000.00 on the primary against 56,071,415,865.09 on OpenCNPJ). Above roughly 100 million BRL, read `shareCapital` as an order-of-magnitude figure, not a cent-exact one.

**What changes on a fallback row.** Comparing every one of the 28 exported fields for all 205 companies, primary row against the same company served by OpenCNPJ during a simulated outage, 5,347 of 5,740 values were identical (93.2%). They fall into four classes, and none of them is a contradictory value: `legalNatureCode` is null on all 205 fallback rows (OpenCNPJ publishes the legal-nature wording but not its code); `address` is filled on 129 fallback rows where the primary left it null, and there was no company where the two mirrors gave different street text; partner age bands read `71 a 80 anos` rather than `Entre 71 a 80 anos`; and the `partners` array can be in a different order — membership was identical for all 59 companies with a quadro societario, but 15 of the 26 with more than one partner listed them in a different sequence, so index into `partners` by name, never by position, if you diff runs against each other. `shareCapital` was identical on all 205 sampled companies; on large capital figures it differs as described above.

Partner names are part of the official public register, and so are the contacts: for a micro-entrepreneur (MEI) the registered `email` and `phone` are usually that person's own address and mobile. minhareceita redacts them; OpenCNPJ, which is where this Actor reads them, publishes them as Receita Federal does. If you do not need them, set `includePartners: false` and `includeContacts: false` and no personal data is written to your dataset. You remain responsible for any personal data you do export, in line with the LGPD. This Actor is independent and is not affiliated with, endorsed by or operated by Receita Federal.

### Frequently asked questions

**Where does the data come from?**

From the Receita Federal do Brasil public CNPJ register, published as open data and read through two independent public mirrors of that same dataset.

**What happens if a CNPJ cannot be found?**

You still get a row, carrying a `lookupError` field. Brazil CNPJ Lookup keeps a strict one-row-in, one-row-out mapping so your input spreadsheet joins back to the output without gaps.

**Can I exclude personal data?**

Yes. Partner names are part of the official public register, but set `includePartners: false` and `includeContacts: false` and no personal data is written to your dataset.

**How current is the register?**

It is a periodic snapshot, not a live feed: the mirrors refresh when Receita Federal publishes a new extract, so a company registered this week may not appear yet.

### Related Actors

Same engine, same official-source approach:

- [**AusTender (Australia)**](https://apify.com/publicdata/austender-australian-government-contracts) — federal contracts, winners and expiry dates
- [**UK Public Tenders**](https://apify.com/publicdata/uk-contracts-finder-find-a-tender) — Contracts Finder and Find a Tender in one run
- [**Swiss Public Tenders (simap.ch)** — tenders and awards with prices, bid counts and weighted criteria](https://apify.com/publicdata/simap-swiss-public-tenders)
- [**Swiss Commercial Register (SHAB)** — new companies, changes, deletions and bankruptcies](https://apify.com/publicdata/shab-swiss-company-gazette)
- [**EU Tenders (TED)** — European procurement notices and contract awards](https://apify.com/publicdata/ted-tenders-eu-procurement)
- [**France Company Register** — SIREN/SIRET, executives, official labels](https://apify.com/publicdata/sirene-siren-french-company-search)
- [**GLEIF LEI** — LEI lookup, lapsed-LEI screening, parent companies](https://apify.com/publicdata/gleif-lei-scraper)

# Actor input Schema

## `cnpjList` (type: `array`):

Brazilian company tax IDs to look up. With or without punctuation — 14 digits each. Head office CNPJs end in 0001-XX.

## `cnpjText` (type: `string`):

Alternative to the field above: paste many CNPJs separated by commas, spaces or new lines (e.g. straight from a spreadsheet column).

## `includePartners` (type: `boolean`):

Include the quadro societário (partners and officers). Names come from the public Receita Federal register.

## `includeContacts` (type: `boolean`):

Include the registered phone number and e-mail address. The primary mirror publishes the e-mail key but never fills it (0 of 205 companies in a live random sample on 2026-08-21), so with this on the Actor spends one extra lookup per company on the OpenCNPJ mirror, which does publish it. Measured on that same sample of 205: phone on 182 rows, e-mail on 149. Leave it off for large runs that do not need contacts - it halves the number of requests.

## `skipInactive` (type: `boolean`):

Drop companies whose registration is not ATIVA. Dropped companies are not exported and not charged; with a Max results cap set, the run reads further down your list to replace them.

## `maxItems` (type: `integer`):

Hard cap on rows exported (0 = unlimited). The run keeps reading down your list until this many rows are exported or the list runs out, so companies dropped by 'Skip inactive companies' are backfilled from the rest of the input.

## Actor input object example

```json
{
  "cnpjList": [
    "19131243000197"
  ],
  "includePartners": true,
  "includeContacts": true,
  "skipInactive": false,
  "maxItems": 0
}
```

# Actor output Schema

## `dataset` (type: `string`):

Companies resolved from CNPJ via Receita Federal open data. Every exported row is one dataset item.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "cnpjList": [
        "19131243000197"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicdata/cnpj-lookup-receita-federal").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "cnpjList": ["19131243000197"] }

# Run the Actor and wait for it to finish
run = client.actor("publicdata/cnpj-lookup-receita-federal").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "cnpjList": [
    "19131243000197"
  ]
}' |
apify call publicdata/cnpj-lookup-receita-federal --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,publicdata/cnpj-lookup-receita-federal"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6oTDJoIgdchWzW0YP/builds/aDvkIIy50SbbtMgOU/openapi.json
