CNPJ válido para testes: algoritmo mod-11 e API REST
CNPJ válido para testes: algoritmo mod-11 e API REST
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:
| Bloco | Posições | Significado |
|---|---|---|
| BB.BBB.BBB | 1–8 | Raiz da empresa (identificador único) |
| FFFF | 9–12 | Filial (0001 para matriz) |
| DD | 13–14 | Dí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.sqlVariá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
calcularDigitocom a regraresto < 2 → 0antes 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.ddo 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
afterAlledocker-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.