# Como validar fornecedor pelo CNPJ: checklist, regras e código

> Checklist para validar fornecedor pelo CNPJ: situação e motivo, situação especial, idade, CNAE, natureza, porte e sócios, com código e reconsulta mensal.

Fonte: https://apipj.com.br/guias/validar-fornecedor-cnpj (atualizado em 10/10/2026)

Antes de cadastrar um fornecedor ou pagar a primeira nota, vale confirmar que o CNPJ existe, está ativo e é de quem você acha que está contratando. Os dados cadastrais públicos da Receita Federal respondem boa parte disso numa consulta só. Este guia liga cada item do checklist a um campo da resposta completa de `GET /v1/cnpj/{cnpj}`, traz as regras em código e mostra o que fica de fora.

## Checklist do fornecedor

| # | O que conferir | Campos da resposta | Regra sugerida |
|---|---|---|---|
| 1 | CNPJ bem formado | `GET /v1/valida/{cnpj}`: `valido`, `erro` | Recusar na digitação. É aberta e não gasta cota |
| 2 | Situação cadastral | `situacao_cadastral`: `codigo`, `descricao`, `data`, `motivo` | `02` ATIVA segue. `01` NULA e `08` BAIXADA: bloquear. `03` SUSPENSA e `04` INAPTA: revisão manual, lendo o motivo |
| 3 | Situação especial | `situacao_especial`: `descricao`, `data` | Qualquer valor preenchido vai para revisão, mesmo com a empresa ATIVA |
| 4 | Idade | `data_inicio_atividade` | Aberta há menos de 180 dias: revisão |
| 5 | Atividade | `cnae_principal`, `cnaes_secundarios` | Algum CNAE compatível com o que você vai comprar; se nenhum for, revisão |
| 6 | Natureza, porte e regime | `natureza_juridica`, `porte`, `capital_social`, `simples`, `mei` | Registrar e usar na sua política de crédito e de limite de pedido |
| 7 | Sócios e quem assina | `socios`: `nome`, `qualificacao`, `data_entrada`; `qualificacao_responsavel` | Quem assina deve aparecer no quadro, ou apresentar procuração |
| 8 | Endereço e contato | `endereco`, `telefones`, `email` | Bater com o contrato, a nota e o cadastro bancário |

Os detalhes que mais pegam:

- **A situação especial aparece em empresa ativa.** Valores como `RECUPERACAO JUDICIAL`, `FALIDO`, `EM LIQUIDACAO`, `LIQUIDACAO EXTRA-JUDICIAL` e `INTERVENCAO` vêm em `situacao_especial.descricao`, com `situacao_cadastral` ainda `02` ATIVA em parte dos casos. Quem olha só a situação cadastral deixa passar.
- **O motivo explica a situação.** Uma INAPTA por `OMISSAO DE DECLARACOES` é um caso diferente de uma BAIXADA por `INCORPORACAO`. O texto vem em `situacao_cadastral.motivo.descricao`, exatamente como a Receita publica.
- **A idade é do estabelecimento.** `data_inicio_atividade` é a abertura daquele CNPJ: uma filial nova de uma empresa antiga também cai na regra dos 180 dias. Nesse caso, consulte a matriz (ordem `0001`) e compare.
- **Empresário individual e MEI costumam não ter quadro de sócios.** O nome do titular está na própria `razao_social`.
- **O CPF do sócio vem mascarado** (no formato `***123456**`), como na base pública. Para comparar uma pessoa, use o nome e a qualificação.

## Código: triagem automática

O módulo abaixo, para Node.js 18 ou mais novo e sem dependências, consulta o CNPJ e devolve `aprovar`, `revisar` ou `bloquear` com os motivos. As regras são uma sugestão de política, não uma regra legal: ajuste prazos e listas ao que a sua empresa decidir.

```js fornecedor.mjs
import { readFile, writeFile } from 'node:fs/promises';

const BASE = 'https://apipj.com.br/v1';
const DIA = 24 * 60 * 60 * 1000;
const espera = (ms) => new Promise((ok) => setTimeout(ok, ms));

// Consulta um CNPJ; null se não estiver na carga do mês. No limite por minuto, espera e repete.
export async function consultar(cnpj) {
  for (;;) {
    const r = await fetch(`${BASE}/cnpj/${encodeURIComponent(cnpj)}`, {
      headers: { Authorization: `Bearer ${process.env.APIPJ_KEY}` },
    });
    if (r.status === 404) return null;
    if (r.status === 429) {
      const erro = await r.json();
      if (erro.code === 'quota_exceeded') throw new Error('Cota do mês esgotada');
      await espera(Number(r.headers.get('retry-after') || 60) * 1000);
      continue;
    }
    if (!r.ok) throw new Error(`apipj: HTTP ${r.status}`);
    return r.json();
  }
}

const normalizar = (s) => String(s || '').normalize('NFD').replace(/[̀-ͯ]/g, '').toUpperCase().replace(/\s+/g, ' ').trim();

export function avaliarFornecedor(e, { cnaesAceitos = [], diasMinimos = 180, assinante = null, hoje = new Date() } = {}) {
  const bloquear = [];
  const revisar = [];
  const sit = e.situacao_cadastral;
  const motivo = sit.motivo.codigo && sit.motivo.codigo !== '00' ? ` (${sit.motivo.descricao})` : '';
  if (sit.codigo === '01' || sit.codigo === '08') bloquear.push(`situação ${sit.descricao} desde ${sit.data}${motivo}`);
  else if (sit.codigo !== '02') revisar.push(`situação ${sit.descricao} desde ${sit.data}${motivo}`);
  if (e.situacao_especial.descricao) {
    revisar.push(`situação especial ${e.situacao_especial.descricao} desde ${e.situacao_especial.data}`);
  }
  const dias = Math.floor((hoje - Date.parse(e.data_inicio_atividade)) / DIA);
  if (!(dias >= diasMinimos)) revisar.push(Number.isNaN(dias) ? 'sem data de início de atividade' : `aberta há ${dias} dias`);
  const cnaes = [e.cnae_principal, ...e.cnaes_secundarios].map((c) => c.codigo).filter(Boolean);
  if (cnaesAceitos.length && !cnaes.some((c) => cnaesAceitos.some((p) => c.startsWith(p)))) {
    revisar.push(`nenhum CNAE começa com ${cnaesAceitos.join(' ou ')}`);
  }
  if (assinante) {
    const nome = normalizar(assinante);
    const noQuadro = e.socios.some((s) => normalizar(s.nome) === nome);
    if (!noQuadro && !normalizar(e.razao_social).includes(nome)) revisar.push('quem assina não está no quadro de sócios');
  }
  const decisao = bloquear.length ? 'bloquear' : revisar.length ? 'revisar' : 'aprovar';
  return { decisao, motivos: [...bloquear, ...revisar] };
}
```

Usando, para um fornecedor de software (CNAE começando com `62` ou `63`):

```js triagem.mjs
import { consultar, avaliarFornecedor } from './fornecedor.mjs';

for (const cnpj of ['11378117000120', '00000000E08G12']) {
  const empresa = await consultar(cnpj);
  console.log(cnpj, empresa ? avaliarFornecedor(empresa, { cnaesAceitos: ['62', '63'] }) : 'fora da carga do mês');
}
```

Saída real, em 10/10/2026:

```text
11378117000120 { decisao: 'aprovar', motivos: [] }
00000000E08G12 {
  decisao: 'revisar',
  motivos: [ 'aberta há 71 dias', 'nenhum CNAE começa com 62 ou 63' ]
}
```

O segundo CNPJ é o primeiro alfanumérico emitido pela Receita, uma filial de banco aberta em 31/07/2026: cai na regra da idade e na da atividade, como deveria para quem compra software. Para incluir a checagem de quem assina, passe `assinante: 'Nome Completo'`.

## Reconsulta mensal da carteira

Os dados abertos do CNPJ mudam uma vez por mês, então reconsultar a carteira todo dia só gasta cota. O caminho econômico é perguntar a `GET /v1/status`, que é aberto e não consome cota, qual é a carga em uso, e reconsultar todos os fornecedores só quando ela mudar. Acrescente ao `fornecedor.mjs`:

```js fornecedor.mjs (continuação)
// Reconsulta a carteira só quando a API já está numa carga nova; guarda a última decisão de cada CNPJ.
export async function reconsultarCarteira(cnpjs, { arquivo = 'carteira.json', porMinuto = 10, ...regras } = {}) {
  const { dataset_month: mes } = await (await fetch(`${BASE}/status`)).json();
  const estado = JSON.parse(await readFile(arquivo, 'utf8').catch(() => '{"fornecedores":{}}'));
  if (estado.mes === mes) return { mes, reconsultados: 0, mudaram: [] };
  const mudaram = [];
  for (const cnpj of cnpjs) {
    const empresa = await consultar(cnpj);
    const atual = empresa ? avaliarFornecedor(empresa, regras) : { decisao: 'revisar', motivos: ['fora da carga do mês'] };
    const antes = estado.fornecedores[cnpj];
    if (antes && antes.decisao !== atual.decisao) mudaram.push({ cnpj, de: antes.decisao, ...atual });
    estado.fornecedores[cnpj] = atual;
    await espera(60000 / porMinuto); // respeita o limite por minuto do plano
  }
  await writeFile(arquivo, JSON.stringify({ ...estado, mes }, null, 2));
  return { mes, reconsultados: cnpjs.length, mudaram };
}
```

- **Agende para rodar todo dia** (cron, agendador de tarefas, um job do seu sistema). Ela só consulta quando a carga muda; nos outros dias, faz uma chamada aberta a `/v1/status` e para.
- **`mudaram` é a lista que importa:** fornecedores que passaram de `aprovar` para `revisar` ou `bloquear` desde a carga anterior, com os motivos.
- **Custo:** uma consulta por fornecedor por mês, inclusive os que voltam 404. O plano gratuito tem 50.000 consultas por mês.
- **Tempo:** o tamanho da carteira dividido pelo limite por minuto do plano. Use em `porMinuto` o limite do seu plano (10 no gratuito); se mesmo assim vier um `429`, `consultar` espera o `Retry-After` e repete.

## O que a API não cobre

A consulta de CNPJ mostra o cadastro público da empresa. Ela **não** traz:

- **Certidão de débitos.** A regularidade fiscal federal se comprova com a [certidão emitida pela Receita Federal e pela PGFN](https://www.gov.br/pt-br/servicos/emitir-certidao-de-regularidade-fiscal). Estados e municípios têm as certidões deles.
- **Protestos.** Ficam nos cartórios de protesto, não na base do CNPJ.
- **Processos judiciais.** Ficam nos tribunais. A situação especial registra casos como falência, recuperação judicial, liquidação e intervenção, não processos em geral.
- **Inscrição estadual.** Vem do cadastro de cada estado.
- **Mudanças de hoje.** A base é a carga mensal dos dados abertos; para prova formal da situação cadastral, use o comprovante emitido no site da Receita, como explica a [API de CNPJ](https://apipj.com.br/api-cnpj#o-que-esta-api-nao-substitui).

Para fornecedores críticos, a consulta pelo CNPJ é o primeiro filtro, não a análise inteira.

## Perguntas frequentes

### A consulta conta como validação de fornecedor para auditoria?

Ela registra o que a Receita publicava na carga do mês (o campo `atualizado_em` diz qual). Guarde a resposta e a data junto do cadastro. Se a sua auditoria exige documento oficial, emita o comprovante e as certidões nos sites dos órgãos.

### Dá para validar o regime tributário do fornecedor?

Dá para ver a opção pelo Simples Nacional e pelo MEI e as datas. O guia da [API do Simples Nacional e MEI](https://apipj.com.br/guias/api-simples-nacional) mostra como ler esses campos e quando conferir no portal oficial.

### E se o fornecedor tiver CNPJ alfanumérico?

Funciona igual: a consulta aceita os dois formatos, e o exemplo acima já usa um. Confira se o seu cadastro aceita letras no campo de CNPJ; o guia do [CNPJ alfanumérico](https://apipj.com.br/cnpj-alfanumerico) tem o checklist.
