← Voltar ao blog

CNPJ válido para testes: algoritmo mod-11 e API REST

·11 min de leitura

Todo CNPJ válido para testes tem 14 dígitos que satisfazem um cálculo mod-11 definido pela Receita Federal. Implementar esse cálculo corretamente — e consumi-lo via API quando o volume exige escala — é o que separa fixtures de teste confiáveis de bugs de validação que aparecem em produção.

O que é um CNPJ válido para fins de teste

Estrutura do CNPJ: 14 dígitos e o que cada bloco significa

O CNPJ segue o padrão BB.BBB.BBB/FFFF-DD:

BlocoPosiçõesSignificado
BB.BBB.BBB1–8Raiz da empresa (identificador único)
FFFF9–12Filial (0001 para matriz)
DD13–14Dígitos verificadores

Os oito primeiros dígitos identificam o contribuinte. Os quatro seguintes identificam o estabelecimento. Os dois últimos são calculados a partir dos doze anteriores via mod-11.

Por que "válido" não significa "real" — a distinção que a LGPD exige

Um CNPJ é matematicamente válido quando seus dígitos verificadores conferem com o algoritmo. Ele não precisa estar cadastrado na Receita Federal para isso. Dados gerados por uma ferramenta como o gerador de CNPJ do FakeForge BR passam em qualquer validador de formato, mas não existem no Cadastro Nacional de Pessoas Jurídicas.

Essa distinção importa juridicamente. A LGPD Art. 5º, I define dado pessoal como "informação relacionada a pessoa natural identificada ou identificável". Um CNPJ fictício não se relaciona a nenhuma entidade real, portanto sai do escopo de proteção da lei para fins de armazenamento em ambiente de teste.

Casos em que um CNPJ inválido quebra o pipeline de testes

Usar sequências como 12345678000100 em fixtures é o erro mais comum. A maioria dos sistemas de ERP, gateways de pagamento e APIs de crédito valida o dígito verificador antes de processar. Um CNPJ inválido retorna erro 400 logo na entrada, mascarando o comportamento real que o teste deveria exercitar.

O algoritmo mod-11 passo a passo

Pesos da primeira rodada (5 4 3 2 9 8 7 6 5 4 3 2)

Multiplicam-se os 12 primeiros dígitos pelos pesos [5,4,3,2,9,8,7,6,5,4,3,2] e somam-se os produtos.

Cálculo do primeiro dígito verificador

resto = soma % 11

Se resto < 2, o primeiro dígito verificador é 0. Caso contrário, é 11 - resto.

Pesos da segunda rodada (6 5 4 3 2 9 8 7 6 5 4 3 2)

Acrescenta-se o primeiro dígito verificador à base e multiplica-se pelos pesos [6,5,4,3,2,9,8,7,6,5,4,3,2].

Cálculo do segundo dígito verificador

A mesma fórmula: resto = soma % 11, com a regra resto < 2 → 0, caso contrário 11 - resto.

Regra do resto menor que 2 — o ponto mais esquecido em implementações

A Receita Federal exige que qualquer resto 0 ou 1 produza dígito 0. Implementações que usam diretamente 11 - resto sem esse condicional geram dígitos 11 ou 10, quebrando a validação. É o bug mais frequente em geradores escritos às pressas.

Implementação do gerador em TypeScript

Gerar os 12 dígitos base aleatórios

function gerarBase(): number[] {
  return Array.from({ length: 12 }, () => Math.floor(Math.random() * 10));
}

Função calcularDigitoVerificador reutilizável

function calcularDigito(digitos: number[], pesos: number[]): number {
  const soma = digitos.reduce((acc, d, i) => acc + d * pesos[i], 0);
  const resto = soma % 11;
  return resto < 2 ? 0 : 11 - resto;
}

Função gerarCNPJ com opção de formatação

export function gerarCNPJ(formatado = false): string {
  const base = gerarBase();

  const pesos1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const d1 = calcularDigito(base, pesos1);

  const pesos2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const d2 = calcularDigito([...base, d1], pesos2);

  const cnpj = [...base, d1, d2].join('');

  if (!formatado) return cnpj;

  return `${cnpj.slice(0, 2)}.${cnpj.slice(2, 5)}.${cnpj.slice(5, 8)}/${cnpj.slice(8, 12)}-${cnpj.slice(12)}`;
}

Função validarCNPJ para usar nos testes de regressão

export function validarCNPJ(cnpj: string): boolean {
  const limpo = cnpj.replace(/\D/g, '');
  if (limpo.length !== 14) return false;
  if (/^(\d)\1{13}$/.test(limpo)) return false; // bloqueia 00000000000000 etc.

  const digitos = limpo.split('').map(Number);

  const pesos1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const d1Esperado = calcularDigito(digitos.slice(0, 12), pesos1);
  if (digitos[12] !== d1Esperado) return false;

  const pesos2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  const d2Esperado = calcularDigito(digitos.slice(0, 13), pesos2);
  return digitos[13] === d2Esperado;
}

CNPJ Alfanumérico vigente a partir de 01/07/2026

O que muda na estrutura com a Instrução Normativa RFB 2.229/2024

A IN RFB 2.229/2024 permite que os oito dígitos da raiz contenham letras maiúsculas (A–Z) além de números. O formato passa a ser AA.AAA.AAA/FFFF-DD, onde A pode ser letra ou dígito. A Receita Federal começará a emitir CNPJs nesse formato em 01/07/2026. O gerador de CNPJ Alfanumérico do FakeForge BR já implementa o novo padrão.

Como o mod-11 se adapta ao novo formato com letras

Cada caractere da raiz recebe um valor numérico para o cálculo: dígitos mantêm seu valor, letras são convertidas pelo índice (A=10, B=11, ..., Z=35). Os pesos e a regra do resto permanecem idênticos. O resultado dos dígitos verificadores continua sendo numérico.

Impacto nos sistemas legados e nos testes que já usam regex \d{14}

Qualquer regex do tipo ^\d{14}$ ou ^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$ vai rejeitar CNPJs alfanuméricos. A correção é substituir \d por [A-Z0-9] na raiz. Sistemas de ERP, ERPs fiscais e bibliotecas de validação precisarão de patch antes de julho de 2026.

AVISO: Se o seu pipeline de CI usa fixtures CNPJ em formato numérico e seu produto processa notas fiscais após 01/07/2026, adicione ao menos um caso de teste com CNPJ alfanumérico antes dessa data.

Geração em lote via API REST

Endpoint GET /api/generate?type=cnpj&quantity=50&format=json

A documentação da API REST descreve todos os parâmetros. Para gerar 50 CNPJs em JSON:

# JSON
curl "https://fakeforge.com.br/api/generate?type=cnpj&quantity=50&format=json"

# CSV com watermark de atribuição
curl "https://fakeforge.com.br/api/generate?type=cnpj&quantity=50&format=csv"

# SQL com CREATE TABLE pronto
curl "https://fakeforge.com.br/api/generate?type=cnpj&quantity=50&format=sql"

Export em CSV com cabeçalho e em SQL com CREATE TABLE pronto

O output SQL da API inclui a declaração da tabela e os INSERTs prontos para executar:

-- Generated by FakeForge BR - free Brazilian test data
-- https://fakeforge.com.br
-- Generated at: 2026-06-03T14:00:00Z
-- License: CC0 (public domain test data)

CREATE TABLE IF NOT EXISTS cnpj_data (
  id SERIAL PRIMARY KEY,
  cnpj VARCHAR(18) NOT NULL
);

INSERT INTO cnpj_data (cnpj) VALUES
  ('12.345.678/0001-95'),
  ('98.765.432/0001-10');

Autenticação e rate limit: 100 chamadas/dia no plano gratuito

O plano gratuito com 100 chamadas/dia não exige cadastro. Para volumes maiores, inclua o header Authorization: Bearer SEU_API_KEY. A chave é gerada no painel após criar conta.

Exemplo com fetch, axios e curl

// fetch (Node 18+)
const response = await fetch(
  'https://fakeforge.com.br/api/generate?type=cnpj&quantity=10&format=json'
);
const { data } = await response.json();
// data: string[]

// axios
import axios from 'axios';
const { data: { data: cnpjs } } = await axios.get(
  'https://fakeforge.com.br/api/generate',
  { params: { type: 'cnpj', quantity: 10, format: 'json' } }
);

Integrar CNPJs gerados no pipeline de CI

Fixture em Jest: beforeAll chamando a API e populando o banco de teste

// cnpj.fixture.ts
let cnpjs: string[] = [];

beforeAll(async () => {
  const res = await fetch(
    'https://fakeforge.com.br/api/generate?type=cnpj&quantity=20&format=json'
  );
  const body = await res.json();
  cnpjs = body.data;
  await db.cnpj.createMany({ data: cnpjs.map(cnpj => ({ cnpj })) });
});

afterAll(async () => {
  await db.cnpj.deleteMany();
});

Seed com o export SQL direto no docker-compose de teste

Salve o output SQL em ./seed/cnpj.sql e monte o arquivo no container do banco:

services:
  db:
    image: postgres:16
    volumes:
      - ./seed/cnpj.sql:/docker-entrypoint-initdb.d/cnpj.sql

Variáveis de ambiente e segredos — onde não guardar o API key

Nunca coloque o API key no docker-compose.yml comitado. Use docker-compose.override.yml (no .gitignore) ou um secret manager. Em GitHub Actions, use ${{ secrets.FAKEFORGE_API_KEY }} injetado via env:.

Validar CNPJs no código antes de persistir

Middleware de validação em Next.js (App Router, route.ts)

// app/api/empresa/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { validarCNPJ } from '@/lib/validators/cnpj';

export async function POST(req: NextRequest) {
  const body = await req.json();
  if (!validarCNPJ(body.cnpj)) {
    return NextResponse.json({ error: 'CNPJ inválido' }, { status: 422 });
  }
  // ...
}

Schema Zod com refinamento mod-11

import { z } from 'zod';
import { validarCNPJ } from '@/lib/validators/cnpj';

export const EmpresaSchema = z.object({
  cnpj: z
    .string()
    .regex(/^[\dA-Z]{14}$|^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/, 'Formato inválido')
    .refine(validarCNPJ, { message: 'Dígitos verificadores inválidos' }),
  razaoSocial: z.string().min(3),
});

Diferença entre validar formato e validar existência na Receita Federal

A função validarCNPJ confirma que os dígitos batem com o algoritmo. Ela não consulta se o CNPJ está ativo na Receita Federal. Para isso existe a API pública do CNPJ (sem SLA e com rate limit baixo). Na maioria dos sistemas de teste, validação de formato é suficiente. Para sistemas fiscais em produção, a consulta à Receita é obrigatória.

Conformidade com a LGPD ao usar CNPJs fictícios

Dado fictício não é dado pessoal — LGPD Art. 5º, I

A LGPD Art. 5º, I define dado pessoal como informação relacionada a pessoa natural identificada ou identificável. Um CNPJ gerado por algoritmo que não existe na Receita Federal não se relaciona a nenhuma entidade. Não há titular. Não há obrigação de base legal para tratamento.

Quando o CNPJ aparece junto de nome real e vira dado pessoal — Art. 7º, IX

Se o fixture combina um CNPJ fictício com o nome real de um sócio (extraído de uma base de produção, por exemplo), o conjunto pode identificar uma pessoa natural via cruzamento com o Quadro de Sócios e Administradores. Nesse caso, o tratamento precisa de base legal conforme o LGPD Art. 7º, IX. Use o gerador de CPF e dados de pessoa fictícios para evitar o problema pela raiz.

Boas práticas de descarte de fixtures após o ciclo de teste

Pipelines que gravam fixtures em banco devem incluir teardown explícito (afterAll, docker-compose down -v). Fixtures em arquivo devem ter TTL no storage (S3 lifecycle policy, por exemplo). Dados fictícios sem vínculo a pessoa real têm risco baixo, mas manter fixtures acumuladas por meses é dívida técnica sem benefício.

Erros comuns e como diagnosticar

Dígito verificador errado por off-by-one no array de pesos

O erro mais frequente é usar o array de pesos com um índice a mais ou a menos. Valide a implementação contra o CNPJ 11.222.333/0001-81, que é um dos exemplos didáticos da Receita Federal com dígitos verificadores conhecidos (8 e 1).

CNPJs com sequência repetida passando em validadores fracos

00000000000000, 11111111111111 e similares satisfazem o algoritmo mod-11 (o resto é sempre consistente com o dígito). Todo validador de produção deve rejeitar explicitamente CNPJs com todos os dígitos iguais. A função validarCNPJ acima inclui essa verificação.

Regex que rejeita o novo formato alfanumérico

// Antes (rejeita CNPJ alfanumérico após 01/07/2026)
const regex = /^\d{14}$/;

// Depois (aceita ambos os formatos)
const regex = /^[A-Z0-9]{14}$|^[A-Z0-9]{2}\.[A-Z0-9]{3}\.[A-Z0-9]{3}\/\d{4}-\d{2}$/;

Resumo

  • Implemente calcularDigito com a regra resto < 2 → 0 antes de qualquer outra coisa; esse condicional é o ponto de falha mais comum.
  • Use o validador de CNPJ do FakeForge para checar sua implementação contra casos de borda (sequências repetidas, CNPJ alfanumérico).
  • Para gerar volume em CI, prefira a API REST com export SQL e monte o arquivo no docker-entrypoint-initdb.d do container de banco.
  • Atualize todas as regex \d{14} para [A-Z0-9]{14} antes de 01/07/2026.
  • Nunca combine CNPJ fictício com nome real de pessoa; use dados de empresa completos gerados juntos para manter consistência e conformidade.
  • Descarte fixtures com afterAll e docker-compose down -v; acúmulo silencioso é dívida técnica.

Perguntas frequentes

Qual é a latência para gerar 10.000 CNPJs via API? Vale a pena cachear localmente em desenvolvimento?+

A API gera ~5.000 CNPJs/segundo em v16 Node. Uma chamada com `quantity=10000` retorna em ~200ms. Cachear localmente (arquivo JSON) só vale se roda testes >50x/dia. Para CI unitário, preferir chamada direta. Para staging que roda 100+ vezes, cache em Redis com TTL de 1h reduz latência.

Como testo CNPJ alfanumérico hoje se a Receita só emite em 01/07/2026?+

O gerador de CNPJ alfanumérico do FakeForge já produz formatos como `A1.B2C.3D4/5678-EF`. Seu teste pode gerar amostra agora com `?format=json&sample_alfanumerico=true` (simulação). Atualize regex antes de julho; use `[A-Z0-9]` na raiz.

Posso fazer teste reproduzível se a API gera valores aleatórios? Preciso hardcodar CNPJs?+

Sim, hardcode para testes críticos (integração, pagamento). Gere fixture estática em setup (`beforeAll`) e reutilize nos testes. Para testes de formato, use seed determinístico (seed=1234 → mesma sequência). Aleatoriedade vale em smoke tests; determinismo em regressão.

Como mostrar erro amigável em PT-BR quando validação Zod rejeita CNPJ do formulário?+

Catch do `ZodError` e mapeie `.errors[0].code` para mensagem: `'invalid_string'` → 'Formato inválido', `'custom'` → 'Dígitos verificadores não conferem'. Use i18n (`next-intl`) para cada error.message. No handler, retorne `{ error: { field: 'cnpj', message: msg } }` e renderize no input.

Se meu CI roda 50 testes paralelos cada um chamando a API, vou estourar limite de 100/dia?+

Sim. Estratégias: (1) Gere fixture bulk antes dos testes, salve em arquivo, use no beforeAll global. (2) Mock a API para testes unitários, API real só em E2E. (3) Ative plano pago (500/dia) em CI=true com variável de env. (4) Batch chamadas em worker separado.