# Consultar CNPJ no Google Planilhas com a função =CNPJ()

> Função =CNPJ() no Google Planilhas com Apps Script: razão social, situação, CNAE e endereço pela API do apipj, com cache e dentro do limite do plano.

Fonte: https://apipj.com.br/guias/consultar-cnpj-google-planilhas (atualizado em 13/10/2026)

Este guia coloca a consulta de CNPJ dentro do Google Planilhas. Você cola um script no Apps Script da planilha e ganha a fórmula `=CNPJ(A2:A; "razao_social")`, que traz razão social, situação cadastral, CNAE, endereço e outros campos da [API de CNPJ do apipj](https://apipj.com.br/api-cnpj), e a `=CNPJ_VALIDO()`, que confere o dígito verificador sem consultar nada. Para listas longas, um menu preenche as colunas ao lado dos CNPJs. Os dados são os dados abertos da Receita Federal, carga de setembro de 2026.

O código foi executado contra a API em 13/10/2026 no Node.js 24.16, com simulações do UrlFetchApp, do CacheService, do PropertiesService e da planilha. Não é um teste dentro do Google Planilhas: se algo se comportar diferente aí, a tabela de [problemas comuns](#problemas-comuns) é o primeiro lugar para olhar.

## O que você ganha

- **`=CNPJ(cnpj; campo)`**: um campo de um CNPJ, ou de uma coluna inteira de CNPJs com uma fórmula só. Aceita CNPJ com ou sem pontuação, numérico ou [alfanumérico](https://apipj.com.br/cnpj-alfanumerico), e CNPJ que virou número na planilha e perdeu os zeros à esquerda.
- **`=CNPJ_VALIDO(cnpj)`**: VERDADEIRO ou FALSO pelo cálculo do dígito verificador, feito na própria planilha. Não chama a API e não gasta cota.
- **Menu apipj**: guarda a chave de API fora das células e preenche, no ritmo do seu plano, as colunas ao lado de uma lista selecionada.
- **Cache de 6 horas**: a mesma consulta, recalculada ou repetida em outra fórmula, não vai de novo à API.

## Antes de começar

1. [Crie uma conta grátis](https://apipj.com.br/criar-conta) e copie a chave (`apipj_live_...`). O plano gratuito tem 10 consultas por minuto e 50.000 por mês.
2. Prefira criar uma chave só para esta planilha, no [painel](https://apipj.com.br/painel) (cada conta pode ter até 5). Se a planilha for compartilhada além do previsto, você revoga essa chave sem mexer nas suas outras integrações.

## Instalar o script

1. Abra a planilha e vá em **Extensões > Apps Script**. Abre o editor com um arquivo `Código.gs`.
2. Apague o conteúdo do arquivo e cole o código da próxima seção inteiro.
3. Clique em **Salvar projeto** (o ícone de disquete) e dê um nome ao projeto, por exemplo "apipj".
4. Volte para a planilha e recarregue a página. Aparece o menu **apipj** ao lado de **Ajuda**.
5. Clique em **apipj > Configurar chave de API**. Na primeira vez, o Google pede autorização: escolha a sua conta e permita. Como o script é seu e não passou pela verificação do Google, aparece o aviso de app não verificado; para seguir, clique em **Avançado** e depois em acessar o projeto. O script só pede acesso a esta planilha (`@OnlyCurrentDoc`) e à internet, para chamar a API.
6. Cole a chave e clique em **OK**.

Pronto: digite `=CNPJ("00.000.000/0001-91")` numa célula vazia. Deve aparecer `BANCO DO BRASIL SA`.

## O código

```js Código.gs
/**
 * apipj: consulta de CNPJ no Google Planilhas.
 * Guia: https://apipj.com.br/guias/consultar-cnpj-google-planilhas
 *
 * @OnlyCurrentDoc
 */

const APIPJ_URL = 'https://apipj.com.br/v1/cnpj/';
const PROP_CHAVE = 'APIPJ_KEY';
const CACHE_SEGUNDOS = 21600;         // 6 horas, o máximo que o CacheService guarda
const PRAZO_FORMULA_MS = 25 * 1000;   // uma função personalizada tem 30 s para responder
const PRAZO_MENU_MS = 5 * 60 * 1000;  // uma execução pelo menu tem 6 min
// Colunas que o menu preenche, na ordem, à direita da coluna selecionada
const COLUNAS_MENU = ['razao_social', 'situacao', 'municipio', 'uf', 'cnae', 'abertura'];

// Campos aceitos em =CNPJ(cnpj; campo), tirados do formato simplificado da API
const principal_ = (d) => (d.atividade_principal || [])[0] || {};
const CAMPOS = {
  cnpj: (d) => d.cnpj,
  razao_social: (d) => d.nome,
  fantasia: (d) => d.fantasia,
  situacao: (d) => d.situacao,
  data_situacao: (d) => d.data_situacao,
  abertura: (d) => d.abertura,
  tipo: (d) => d.tipo,
  porte: (d) => d.porte,
  natureza_juridica: (d) => d.natureza_juridica,
  cnae: (d) => principal_(d).code,
  cnae_descricao: (d) => principal_(d).text,
  logradouro: (d) => d.logradouro,
  numero: (d) => d.numero,
  complemento: (d) => d.complemento,
  bairro: (d) => d.bairro,
  municipio: (d) => d.municipio,
  uf: (d) => d.uf,
  cep: (d) => d.cep,
  endereco: (d) => [[d.logradouro, d.numero, d.complemento].filter(Boolean).join(', '), d.bairro,
    [d.municipio, d.uf].filter(Boolean).join('/'), d.cep].filter(Boolean).join(' - '),
  telefone: (d) => d.telefone,
  email: (d) => d.email,
  capital_social: (d) => (d.capital_social == null ? '' : Number(d.capital_social)),
  simples: (d) => (d.simples ? (d.simples.optante ? 'Sim' : 'Não') : ''),
  mei: (d) => (d.simei ? (d.simei.optante ? 'Sim' : 'Não') : ''),
};

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('apipj')
    .addItem('Configurar chave de API', 'configurarChave')
    .addItem('Preencher colunas ao lado da seleção', 'preencherSelecao')
    .addSeparator()
    .addItem('Remover chave de API', 'removerChave')
    .addToUi();
}

function configurarChave() {
  const ui = SpreadsheetApp.getUi();
  const r = ui.prompt('Chave de API do apipj',
    'Cole a chave (apipj_live_...). Ela fica nas propriedades do script desta planilha, fora das células.',
    ui.ButtonSet.OK_CANCEL);
  if (r.getSelectedButton() !== ui.Button.OK) return;
  const chave = r.getResponseText().trim();
  if (!/^apipj_live_\S+$/.test(chave)) {
    ui.alert('A chave começa com apipj_live_. Nada foi salvo.');
    return;
  }
  PropertiesService.getScriptProperties().setProperty(PROP_CHAVE, chave);
  ui.alert('Chave salva. As fórmulas =CNPJ desta planilha já podem consultar.');
}

function removerChave() {
  PropertiesService.getScriptProperties().deleteProperty(PROP_CHAVE);
  SpreadsheetApp.getUi().alert('Chave removida desta planilha.');
}

/**
 * Dados de um CNPJ, ou de uma coluna de CNPJs, pela API do apipj.
 *
 * @param {string|string[][]} cnpj CNPJ ou intervalo com CNPJs, com ou sem pontuação.
 * @param {string|string[][]} campo Campo a devolver (padrão: razao_social), ou um intervalo com nomes de campos.
 * @return Valor do campo; para um intervalo, uma coluna (ou uma tabela) de valores.
 * @customfunction
 */
function CNPJ(cnpj, campo) {
  const nome = (c) => String(c).trim().toLowerCase();
  const campos = Array.isArray(campo) ? campo.flat().map(nome)
    : [campo == null || campo === '' ? 'razao_social' : nome(campo)];
  campos.forEach((c) => {
    if (c !== '' && !CAMPOS[c]) throw new Error('Campo desconhecido: ' + c + '. Use: ' + Object.keys(CAMPOS).join(', '));
  });
  const linhas = Array.isArray(cnpj) ? cnpj : [[cnpj]];
  const validos = linhas.flat().map(normalizarCnpj_).filter(cnpjValido_);
  const chave = PropertiesService.getScriptProperties().getProperty(PROP_CHAVE);
  const res = consultarLista_(validos, chave, Date.now() + PRAZO_FORMULA_MS);
  const saida = campos.length === 1
    ? linhas.map((l) => l.map((v) => celula_(v, campos[0], res)))
    : linhas.map((l) => campos.map((c) => celula_(l[0], c, res)));
  return Array.isArray(cnpj) || campos.length > 1 ? saida : saida[0][0];
}

/**
 * Confere o dígito verificador do CNPJ (numérico ou alfanumérico) sem consultar a API.
 *
 * @param {string|string[][]} cnpj CNPJ ou intervalo com CNPJs.
 * @return VERDADEIRO se o CNPJ é válido; para um intervalo, uma coluna de resultados.
 * @customfunction
 */
function CNPJ_VALIDO(cnpj) {
  const f = (v) => {
    const c = normalizarCnpj_(v);
    return c === '' ? '' : cnpjValido_(c);
  };
  return Array.isArray(cnpj) ? cnpj.map((l) => l.map(f)) : f(cnpj);
}

/** Menu: preenche COLUNAS_MENU à direita da coluna selecionada, só nas linhas em que elas estão vazias. */
function preencherSelecao() {
  const ui = SpreadsheetApp.getUi();
  const prazo = Date.now() + PRAZO_MENU_MS;
  const sel = SpreadsheetApp.getActiveRange();
  if (!sel || sel.getNumColumns() !== 1) {
    ui.alert('Selecione só a coluna com os CNPJs (uma coluna, quantas linhas quiser).');
    return;
  }
  const chave = PropertiesService.getScriptProperties().getProperty(PROP_CHAVE);
  if (!chave) {
    ui.alert('Configure a chave primeiro: menu apipj > Configurar chave de API.');
    return;
  }
  const n = COLUNAS_MENU.length;
  const destino = sel.offset(0, 1, sel.getNumRows(), n);
  const entrada = sel.getValues().map((l) => l[0]);
  const atuais = destino.getValues();
  // Linha com qualquer valor nas colunas de destino fica como está: nada é sobrescrito, e é assim que
  // uma nova execução continua de onde a anterior parou.
  const pendentes = entrada.map((v, i) => i).filter((i) => entrada[i] !== '' && atuais[i].every((x) => x === ''));
  if (!pendentes.length) {
    ui.alert('Nada a preencher: as linhas selecionadas já têm valores nas ' + n + ' colunas à direita.');
    return;
  }
  SpreadsheetApp.getActive().toast(pendentes.length + ' linha(s) a preencher.', 'apipj', 5);
  let feitas = 0;
  let falhas = 0;
  let motivo = '';
  for (const i of pendentes) {
    const c = normalizarCnpj_(entrada[i]);
    let linha;
    if (!cnpjValido_(c)) {
      linha = /cnpj/i.test(String(entrada[i])) ? COLUNAS_MENU.slice() : ['CNPJ inválido'];
    } else {
      const r = consultarLista_([c], chave, prazo)[c];
      if (r.parar) {
        motivo = r.erro;
        break;
      }
      if (r.erro) {
        falhas++; // fica em branco e entra na próxima execução
        continue;
      }
      linha = r.dados ? COLUNAS_MENU.map((k) => r.dados[k]) : ['não encontrado'];
    }
    while (linha.length < n) linha.push('');
    const alvo = destino.offset(i, 0, 1, n);
    // Texto puro, para o Planilhas não converter datas, CEP e CNAE (capital_social continua número)
    COLUNAS_MENU.forEach((campo, j) => {
      if (campo !== 'capital_social') alvo.offset(0, j, 1, 1).setNumberFormat('@');
    });
    alvo.setValues([linha]);
    feitas++;
  }
  const faltam = pendentes.length - feitas;
  let msg = feitas + ' linha(s) preenchida(s).';
  if (motivo) msg += ' Parou: ' + motivo + '.';
  if (falhas) msg += ' ' + falhas + ' com erro temporário ficaram em branco.';
  if (faltam) msg += ' Faltam ' + faltam + ': rode o menu de novo com a mesma seleção para continuar.';
  ui.alert(msg);
}

// Consulta CNPJs já normalizados e válidos: cache primeiro, depois a API, até o prazo.
// Devolve { CNPJ: {dados} | {dados: null} (não encontrado) | {erro, parar} }.
function consultarLista_(cnpjs, chave, prazo) {
  const unicos = Array.from(new Set(cnpjs));
  const cache = CacheService.getScriptCache();
  const guardados = unicos.length ? cache.getAll(unicos.map((c) => 'apipj:' + c)) : {};
  const res = {};
  let parada = chave ? '' : 'Configure a chave: menu apipj > Configurar chave de API';
  for (const c of unicos) {
    const g = guardados['apipj:' + c];
    if (g) {
      res[c] = JSON.parse(g);
      continue;
    }
    if (!parada) {
      const r = consultarApi_(c, chave, prazo);
      if (!r.parar) {
        res[c] = r;
        if (!r.erro) cache.put('apipj:' + c, JSON.stringify(r), CACHE_SEGUNDOS);
        continue;
      }
      parada = r.erro;
    }
    res[c] = { erro: parada, parar: true };
  }
  return res;
}

function consultarApi_(c, chave, prazo) {
  const cache = CacheService.getScriptCache();
  for (;;) {
    // Se outra fórmula ou execução já esgotou o limite por minuto, espera a pausa ou desiste antes do prazo
    const pausa = Number(cache.get('apipj:pausa') || 0);
    if (pausa > Date.now()) {
      if (pausa > prazo) return { erro: 'Limite por minuto do plano atingido, tente de novo em 1 minuto', parar: true };
      Utilities.sleep(Math.max(0, pausa - Date.now()));
    }
    if (Date.now() > prazo) return { erro: 'Tempo esgotado, tente de novo', parar: true };
    let r;
    try {
      r = UrlFetchApp.fetch(APIPJ_URL + c + '?formato=simplificado', {
        headers: { Authorization: 'Bearer ' + chave },
        muteHttpExceptions: true,
      });
    } catch (e) {
      return { erro: 'Falha de rede, tente de novo' };
    }
    const status = r.getResponseCode();
    let corpo = {};
    try {
      corpo = JSON.parse(r.getContentText());
    } catch (e) {
      // corpo vazio ou fora do JSON
    }
    if (status === 429 && corpo.code === 'rate_limited') {
      pausar_(cache, Number(cabecalho_(r, 'retry-after')) || 1);
      continue;
    }
    // Última consulta do minuto: as próximas esperam o limite zerar, em vez de receber 429
    if (cabecalho_(r, 'x-ratelimit-remaining') === '0') pausar_(cache, Number(cabecalho_(r, 'x-ratelimit-reset')) || 1);
    if (status === 200) return { dados: resumir_(corpo) };
    if (status === 404) return { dados: null };
    if (status === 400) return { erro: 'CNPJ inválido' };
    if (status === 401) return { erro: 'Chave de API inválida ou revogada', parar: true };
    if (status === 429) return { erro: 'Cota do mês esgotada (apipj.com.br/precos)', parar: true };
    return { erro: 'Erro ' + status + ' na consulta, tente de novo' };
  }
}

function pausar_(cache, segundos) {
  cache.put('apipj:pausa', String(Date.now() + segundos * 1000), Math.ceil(segundos) + 1);
}

function cabecalho_(resposta, nome) {
  const h = resposta.getHeaders();
  for (const k in h) if (k.toLowerCase() === nome) return String(h[k]);
  return '';
}

// Guarda no cache só os campos de CAMPOS (sem o quadro de sócios): cada item fica bem abaixo de 100 KB
function resumir_(d) {
  const o = {};
  Object.keys(CAMPOS).forEach((k) => {
    const v = CAMPOS[k](d);
    o[k] = v == null ? '' : v;
  });
  return o;
}

function celula_(valor, campo, res) {
  const c = normalizarCnpj_(valor);
  if (c === '' || campo === '') return '';
  if (!cnpjValido_(c)) return 'CNPJ inválido';
  const r = res[c];
  if (r.erro) return r.erro;
  return r.dados ? r.dados[campo] : 'não encontrado';
}

function normalizarCnpj_(valor) {
  if (valor == null || valor === '') return '';
  // Célula numérica perde os zeros à esquerda: 191 é 00.000.000/0001-91
  if (typeof valor === 'number') return String(Math.round(valor)).padStart(14, '0');
  const c = String(valor).replace(/[^0-9A-Za-z]/g, '').toUpperCase();
  return /^[0-9]{11,13}$/.test(c) ? c.padStart(14, '0') : c;
}

// Dígitos verificadores, numérico ou alfanumérico: valor de cada caractere = código ASCII - 48
function cnpjValido_(c) {
  if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(c) || /^0+$/.test(c)) return false;
  const v = c.split('').map((ch) => ch.charCodeAt(0) - 48);
  const pesos = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const dv = (n) => {
    let soma = 0;
    for (let i = 0; i < n; i++) soma += v[i] * pesos[i + 13 - n];
    const resto = soma % 11;
    return resto < 2 ? 0 : 11 - resto;
  };
  return v[12] === dv(12) && v[13] === dv(13);
}
```

Escolhas que importam:

- **A chave fica nas propriedades do script, não nas células nem no código.** Ela é lida pela fórmula e pelo menu. Veja abaixo [quem consegue ver a chave](#quem-ve-a-sua-chave).
- **CNPJ inválido não sai da planilha.** O dígito verificador é conferido antes; inválidos, vazios e repetidos não gastam cota.
- **Cache de 6 horas por CNPJ**, compartilhado entre as fórmulas e o menu. É o máximo do CacheService, que guarda até 1.000 itens e pode descartar antes do prazo; por isso o cache economiza recálculos, mas não substitui gravar os valores na planilha.
- **Limite por minuto respeitado.** Quando a API avisa que a consulta foi a última do minuto, ou responde 429 `rate_limited`, o script anota uma pausa que vale para todas as fórmulas e espera o tempo pedido, se couber no prazo. Cota do mês esgotada (429 `quota_exceeded`) e chave inválida (401) param na hora, sem insistir.

## Usar a função =CNPJ

No Google Planilhas em português, os argumentos são separados por ponto e vírgula. O primeiro argumento é o CNPJ (ou um intervalo); o segundo, o campo, que pode ficar de fora para trazer a razão social:

```text
=CNPJ("11.378.117/0001-20")                → LEADS2B S/A
=CNPJ(A2; "situacao")                      → ATIVA
=CNPJ(A2; "municipio")                     → CURITIBA
=CNPJ_VALIDO("12.ABC.345/01DE-35")         → VERDADEIRO
```

| Campo | O que vem | Exemplo (00.000.000/0001-91) |
|---|---|---|
| `razao_social` | Razão social (padrão) | BANCO DO BRASIL SA |
| `fantasia` | Nome fantasia | DIRECAO GERAL |
| `situacao` | ATIVA, BAIXADA, INAPTA, SUSPENSA ou NULA | ATIVA |
| `data_situacao` | Data da situação cadastral | 03/11/2005 |
| `abertura` | Data de abertura | 01/08/1966 |
| `tipo` | MATRIZ ou FILIAL | MATRIZ |
| `porte` | Porte declarado | DEMAIS |
| `natureza_juridica` | Código e descrição | 203-8 - Sociedade de Economia Mista |
| `cnae` / `cnae_descricao` | CNAE principal | 64.22-1-00 / Bancos múltiplos, com carteira comercial |
| `logradouro`, `numero`, `complemento`, `bairro` | Endereço, campo a campo | ASA NORTE (bairro) |
| `municipio` / `uf` / `cep` | Cidade, estado e CEP | BRASILIA / DF / 70.040-912 |
| `endereco` | Endereço inteiro numa célula | logradouro, número, complemento - bairro - cidade/UF - CEP |
| `telefone` / `email` | Contato declarado à Receita, quando há | |
| `capital_social` | Capital social, como número | 120000000000 |
| `simples` / `mei` | Optante pelo Simples Nacional e pelo MEI | Não / Não |
| `cnpj` | CNPJ com máscara | 00.000.000/0001-91 |

Um CNPJ válido que não está na carga do mês volta como `não encontrado`; um com dígito errado, como `CNPJ inválido`, sem consulta. Datas e CEP vêm como texto, já formatados.

### Uma fórmula por coluna, não uma por célula

Este é o ponto que mais pesa no limite por minuto. O Google Planilhas executa cada fórmula personalizada separadamente e ao mesmo tempo: `=CNPJ(A2)` arrastada por 200 linhas dispara 200 execuções juntas, que esbarram no limite do plano em segundos, e as que não couberem ficam com a mensagem de limite. Em vez disso, use **uma fórmula para a coluna inteira**:

```text
B2:  =CNPJ(A2:A; "razao_social")
```

Uma execução só, que lê a coluna, separa os válidos, tira os repetidos, aproveita o cache e consulta o resto em sequência, no ritmo do plano. Para várias colunas, escreva os nomes dos campos na linha de cabeçalho e passe esse intervalo como segundo argumento:

```text
     A                    B              C          D           E
1    CNPJ                 razao_social   situacao   municipio   uf
2    00.000.000/0001-91   =CNPJ(A2:A; B1:E1)
3    11.378.117/0001-20
```

A fórmula em B2 preenche B, C, D e E de todas as linhas com uma consulta por CNPJ, não uma por campo. As células à direita e abaixo de B2 precisam estar vazias.

Uma função personalizada tem 30 segundos para responder. Na prática, uma recalculada consulta perto do limite por minuto do plano em CNPJs novos (os que já estão no cache não contam); os que não couberem ficam com `Limite por minuto do plano atingido, tente de novo em 1 minuto`. Para buscar o restante, apague a fórmula e escreva de novo (ou recorte e cole a célula): os CNPJs já consultados vêm do cache e a execução segue com os que faltam. Se a lista tem mais que algumas dezenas de CNPJs, use o menu, descrito abaixo.

A fórmula recalcula quando um CNPJ do intervalo muda. Depois das 6 horas do cache, um recálculo consulta de novo e conta na cota. Quando os dados não precisam mudar, copie e cole como valores (**Editar > Colar especial > Somente valores**) ou use o menu, que grava valores fixos.

## Validar sem consultar: =CNPJ_VALIDO

`=CNPJ_VALIDO(A2:A)` devolve VERDADEIRO ou FALSO para cada linha, com o mesmo cálculo de dígito verificador da API, inclusive para o CNPJ alfanumérico. Não usa a chave nem a internet: serve para limpar uma lista antes de consultar ou para destacar CNPJs digitados errado com formatação condicional. CNPJ com todos os dígitos zero é inválido, como na API.

## Listas longas: preencher pelo menu

Para centenas ou milhares de linhas, o menu é mais adequado que a fórmula: ele grava valores fixos nas células e tem até 6 minutos por execução, em vez de 30 segundos.

1. Selecione a coluna dos CNPJs (por exemplo, `A1:A500`; o cabeçalho pode entrar na seleção).
2. Clique em **apipj > Preencher colunas ao lado da seleção**.
3. O script preenche as 6 colunas à direita com `razao_social`, `situacao`, `municipio`, `uf`, `cnae` e `abertura`. Na linha do cabeçalho (uma célula com "CNPJ"), escreve os nomes dos campos.

Para mudar as colunas, edite a lista `COLUNAS_MENU` no topo do código. O menu nunca sobrescreve: uma linha com qualquer valor nas colunas de destino é pulada. É isso que permite continuar uma lista longa. Cada execução consulta por até 5 minutos, no ritmo do plano (até 5 vezes o limite por minuto); ao parar, ela mostra quantas linhas faltam, e basta rodar o menu de novo com a mesma seleção. Para refazer uma linha, apague as células dela nas colunas de destino.

Erros temporários (falha de rede, erro 5xx) deixam a linha em branco, para entrar na próxima execução. Se a sua lista é grande e você não quer rodar o menu várias vezes, a [consulta de CNPJ em lote](https://apipj.com.br/consulta-cnpj-em-lote) do site faz o mesmo trabalho numa aba do navegador, até o fim, e devolve um CSV.

## Limites

| Limite | Valor | Onde aparece |
|---|---|---|
| Consultas por minuto | o do seu plano (10 no Gratuito) | `Limite por minuto do plano atingido` |
| Consultas por mês | o do seu plano (50.000 no Gratuito) | `Cota do mês esgotada` |
| Tempo de uma fórmula personalizada | 30 segundos (Google) | o script para em 25 s e avisa |
| Tempo de uma execução pelo menu | 6 minutos (Google) | o script para em 5 min e diz quantas linhas faltam |
| Chamadas externas do Apps Script | 20.000 por dia em conta Google pessoal, 100.000 no Google Workspace | erro do Google na fórmula |
| Cache | 6 horas por CNPJ, até 1.000 itens | consulta de novo, e conta na cota |

Cada CNPJ válido consultado conta uma vez na cota, encontrado ou não. O limite por minuto e a cota do mês são da sua conta apipj e somam as consultas da planilha com as da API, do site e de outras chaves.

## Precisa de mais consultas por minuto?

Se a mensagem de limite por minuto aparece com frequência, ou se a cota acaba antes do fim do mês, o caminho é trocar de plano. O checkout abre direto, e a mesma chave passa a ter o limite novo assim que o pagamento é confirmado, sem mudar nada no script:

| Plano | Consultas por minuto | Consultas por mês | Preço | Assinar |
|---|---|---|---|---|
| Gratuito | 10 | 50.000 | grátis | [criar conta](https://apipj.com.br/criar-conta) |
| Dev | 30 | 200.000 | R$ 12,90/mês | [assinar o Dev](https://apipj.com.br/painel?assinar=dev) |
| Pro | 200 | 600.000 | R$ 59,90/mês | [assinar o Pro](https://apipj.com.br/painel?assinar=pro) |

Se você ainda não estiver logado, o link pede o login e volta direto para o pagamento. Detalhes em [preços](https://apipj.com.br/precos).

## Quem vê a sua chave

A chave fica nas propriedades do script, uma por planilha, e não aparece nas células. Mas o Apps Script de uma planilha tem as mesmas permissões da planilha, então:

- **Quem pode editar a planilha** abre o Apps Script, vê a chave em **Configurações do projeto > Propriedades do script** e consegue consultar com ela. Todas as fórmulas `=CNPJ` da planilha, de qualquer editor, gastam a cota da sua conta. Só dê acesso de edição a quem pode usar a sua chave.
- **Quem só pode ver ou comentar** não abre o editor nem as propriedades, mas pode fazer uma cópia da planilha, que leva junto o projeto do Apps Script. Não conte com a chave ficando de fora da cópia: antes de compartilhar com quem pode copiar, ou de usar a planilha como modelo, clique em **apipj > Remover chave de API**. Nas configurações de compartilhamento, também dá para impedir que leitores façam cópia.
- **Por que não as propriedades do usuário.** Numa função personalizada, `getUserProperties()` devolve as propriedades do dono da planilha, não as de quem digitou a fórmula. Se cada editor guardasse a própria chave ali, o menu usaria a chave de quem o executa, mas as fórmulas usariam a do dono, sem ninguém perceber. Com as propriedades do script, há uma chave só por planilha, e fica claro quem a usa.
- **Se a chave vazar,** revogue no [painel](https://apipj.com.br/painel) (a revogação é imediata), crie outra e configure de novo pelo menu.

O que sai da planilha são só os CNPJs válidos, enviados à API do apipj pelos servidores do Google. As demais colunas não saem. O script guarda no cache os campos da tabela acima, sem o quadro de sócios.

## Problemas comuns

| O que aparece | Causa | O que fazer |
|---|---|---|
| Menu apipj não aparece | A planilha não foi recarregada depois de salvar o script | Salve o projeto no Apps Script e recarregue a aba da planilha |
| `#NOME?` na fórmula | O script não foi salvo, ou está em outra planilha | Uma função personalizada só existe na planilha onde o script foi colado |
| `Configure a chave: menu apipj > Configurar chave de API` | Nenhuma chave salva nesta planilha | Configure pelo menu; numa cópia da planilha, configure de novo |
| `Chave de API inválida ou revogada` | Chave digitada errado, revogada ou de outra conta | Copie a chave do [painel](https://apipj.com.br/painel) e configure de novo |
| `CNPJ inválido` | Dígito verificador não confere, ou texto que não é CNPJ | Confira com `=CNPJ_VALIDO`; nada foi cobrado |
| `não encontrado` | CNPJ válido, mas fora da carga do mês (empresa nova, por exemplo) | Confira no site da Receita; contou uma consulta |
| `Limite por minuto do plano atingido...` | Muitas consultas no mesmo minuto, em geral por usar uma fórmula por célula | Troque por uma fórmula por coluna ou use o menu; recalcule depois de 1 minuto |
| `Cota do mês esgotada...` | A cota mensal da conta acabou | Espere o dia 1º ou [troque de plano](#precisa-de-mais-consultas-por-minuto) |
| `#ERRO!` com "Campo desconhecido" | Nome de campo fora da tabela | Use um dos nomes da tabela de campos, sem acento |
| `#REF!` | A fórmula com intervalo não tem espaço para crescer | Esvazie as células à direita e abaixo da fórmula |
| A célula mostra `191` em vez de `00000000000191` | A coluna está como número e perdeu os zeros à esquerda | A fórmula completa os zeros e consulta certo; para exibir o CNPJ inteiro, formate a coluna como texto simples antes de colar |

## Próximos passos

- [Consulta de CNPJ em lote](https://apipj.com.br/consulta-cnpj-em-lote): cole a lista no navegador e baixe um CSV, sem script.
- [Documentação da API](https://apipj.com.br/docs): todos os campos, os formatos `completo` e `simplificado` e os cabeçalhos de limite.
- [Validar fornecedor pelo CNPJ](https://apipj.com.br/guias/validar-fornecedor-cnpj): o que conferir numa lista de fornecedores.
- Em código: [Python](https://apipj.com.br/guias/consultar-cnpj-python), [JavaScript](https://apipj.com.br/guias/consultar-cnpj-javascript), [PHP](https://apipj.com.br/guias/consultar-cnpj-php), [C#](https://apipj.com.br/guias/consultar-cnpj-csharp).
