CNPJ Alfanumérico — Documentação Técnica
Este guia é o companheiro técnico do Comunicado. Se você é desenvolvedor ou arquiteto e precisa adaptar uma integração, é aqui que estão os contratos JSON, os comportamentos por produto e o checklist de migração.
Base regulatória: IN RFB 2.229/2024 · NT Conjunta ENCAT 2025.001 v1.00.
Índice
- Visão geral em 30 segundos
- O novo formato do CNPJ
- O princípio de versionamento da NFE.io
- O que muda no contrato da API
- Mudanças por produto
- Webhooks
- Códigos de status e mensagens de erro
- Checklist de preparação
- Cenários de teste em homologação
- Perguntas frequentes
1. Visão geral em 30 segundos
A partir de julho de 2026, a Receita Federal passa a emitir CNPJs que podem conter letras. Isso afeta diretamente quem já integra com a gente — então a pergunta que guiou todo o nosso desenho foi: como dar suporte ao formato novo sem que ninguém precise mexer no que já funciona hoje?
A resposta foi criar uma V3 das APIs, com uma regra simples de entender:
| Versão | Status | Tipo de federalTaxNumber na request | Tipo na response/webhook |
|---|---|---|---|
| V1 | congelada | number | number |
| V2 | congelada (boundary defensivo) | number | number |
| V3 | nova | string (aceita number por compatibilidade na entrada) | sempre string |
Se você guardar só uma frase deste documento, que seja esta:
Mantra: "V2 nunca enxerga CNPJ alfa. V3 é alfa-aware."
2. O novo formato do CNPJ
2.1 Especificação
O CNPJ continua com 14 posições, mas agora as 12 primeiras podem misturar letras e números. Só os dois dígitos verificadores no final permanecem estritamente numéricos:
14 posições totais
├── 12 alfanuméricas (raiz 8 + ordem 4) — pode conter [A-Z0-9]
└── 2 numéricas (dígitos verificadores) — sempre [0-9]
Letras vedadas: I, O, U, Q, F
(evitam confusão visual com 0 e 1)
Regex efetiva: ^[A-HJ-NPRT-Z0-9]{12}[0-9]{2}$
2.2 Exemplos
Lado a lado, fica fácil ver a diferença:
CNPJ numérico legado: 12345678000199 (14 dígitos)
CNPJ alfanumérico: 12ABC345000ABC (12 alfanum + 2 dígitos)
2.3 Algoritmo do dígito verificador
O cálculo continua sendo o bom e velho Módulo 11 — a novidade é que os pesos passam a ser aplicados sobre o valor ASCII menos 48 de cada caractere. Na prática, isso faz os dígitos 0–9 continuarem valendo 0–9 e dá um valor numérico para cada letra:
'0' (ASCII 48) → 0
'9' (ASCII 57) → 9
'A' (ASCII 65) → 17
'Z' (ASCII 90) → 42
Se você valida o dígito verificador no seu lado, precisa atualizar esse algoritmo. Nossa recomendação, porém, é não reinventar a roda: delegue para uma biblioteca oficial de validação de CNPJ da sua linguagem. Assim você não precisa se preocupar com os detalhes do cálculo.
3. O princípio de versionamento da NFE.io
3.1 Tabela canônica
Esta tabela resume, camada por camada, o que acontece quando um CNPJ alfanumérico encontra cada versão da API. A leitura é direta: na coluna legado, o sistema protege você do formato novo; na coluna V3, ele o entrega de forma consistente.
| Camada | V1 / V2 (legado) | V3 (alfa-aware) |
|---|---|---|
| API de Empresas (cadastro) | empresa alfa → 404 Not Found | aceita, response string |
| Emissão de NF-e/NFC-e | issuer alfa → 400 Bad Request | aceita, response string |
| Emissão de NFS-e | issuer alfa → 400 Bad Request | aceita, response string |
| Distribuição de Documentos Fiscais (inbound) | nota alfa → ignorada silenciosamente | aparece normalmente, response string |
| Webhook | nota alfa → não envia para subscriber V2 | envia string |
| API de Consulta de Notas | CNPJ alfa → 404 Not Found | aceita, response string |
| Response JSON | sempre number | sempre string |
3.2 Por que desenhamos assim
Três objetivos guiaram esse desenho — e vale a pena entender cada um, porque eles explicam praticamente todo o comportamento descrito neste documento:
- Zero regressão. Para clientes V1/V2, nada muda — nem no schema, nem no tipo do campo, nem no comportamento. Quem está integrado hoje pode ignorar tranquilamente toda essa mudança.
- Sem flags, sem espera. Não existe feature flag, whitelist nem código
412para "habilitar" o alfa. Quem decide quando o alfa entra em produção é a SEFAZ (e as prefeituras): no instante em que elas liberam o XSD alfa, o sistema NFE.io passa a autorizar (cStat=100) automaticamente, sem nenhuma intervenção manual da nossa parte. - Determinístico. A V3 não escolhe o tipo do JSON conforme o valor do CNPJ — ele é sempre
string. Isso significa que seu parser nunca precisa lidar com union types nem adivinhar o formato; é texto, ponto.
4. O que muda no contrato da API
4.1 Request — V3 aceita os dois tipos
Para facilitar a sua vida na migração, a V3 é flexível na entrada: ela aceita federalTaxNumber como string (o jeito recomendado) ou como number (por compatibilidade, útil enquanto você ainda tem código antigo). Internamente, tudo é normalizado para string.
// ✅ Recomendado (V3)
{
"federalTaxNumber": "12ABC345000ABC"
}
// ✅ Também aceito (V3, compat — para CNPJ numérico)
{
"federalTaxNumber": 12345678000199
}
// ❌ V2 rejeita string com letras
{
"federalTaxNumber": "12ABC345000ABC" // → 400 Bad Request
}
4.2 Response — V3 sempre string
Na saída, a V3 é rígida de propósito: sempre string, seja o CNPJ numérico ou alfanumérico. Essa consistência é o que permite que o seu parser não tenha surpresas.
// V2 (hoje e amanhã — congelada)
{
"id": "...",
"federalTaxNumber": 12345678000199, // number
"name": "Empresa Exemplo S.A."
}
// V3 — CNPJ numérico
{
"id": "...",
"federalTaxNumber": "12345678000199", // string
"name": "Empresa Exemplo S.A."
}
// V3 — CNPJ alfanumérico
{
"id": "...",
"federalTaxNumber": "12ABC345000ABC", // string
"name": "Empresa Nova Ltda."
}
4.3 Selecionando a versão
A versão é escolhida por path na URL (/v2/ ou /v3/) ou por header, dependendo de cada produto. Os detalhes estão na seção Mudanças por produto.
5. Mudanças por produto
A regra geral é sempre a mesma, mas cada produto tem suas particularidades. Veja a sua abaixo.
5.1 API de Empresas (cadastro)
Endpoint base: https://api.nfe.io/v{version}/companies
| Operação | V2 (legado) | V3 (alfa-aware) |
|---|---|---|
POST /companies com CNPJ numérico | 201 Created, response number | 201 Created, response string |
POST /companies com CNPJ alfa | n/a — não pode mandar string com letras (400) | 201 Created, response string |
GET /companies/{id} de empresa numérica | 200 OK, federalTaxNumber: number | 200 OK, federalTaxNumber: string |
GET /companies/{id} de empresa alfa | 404 Not Found | 200 OK, federalTaxNumber: string |
GET /companies?federalTaxNumber=12ABC... | 404 | 200 OK |
Importante: uma empresa alfa cadastrada via V3 continua existindo no banco — ela só é invisível para a V2. Se o cliente da V2 tentar consultá-la, recebe
404. Isso não é bug: é exatamente o princípio "V2 nunca vê alfa" em ação.
5.2 API de NF-e / NFC-e
Endpoint base: https://api.nfe.io/v{version}/companies/{companyId}/productinvoices
| Cenário | V2 | V3 |
|---|---|---|
Emissão com issuer.federalTaxNumber numérico | ✅ normal | ✅ normal, response string |
Emissão com issuer.federalTaxNumber alfa | 400 Bad Request: {"message":"Use V3 for alphanumeric CNPJ"} | ✅ chave de acesso gerada com DV ASCII−48, XML enviado à SEFAZ |
| Consulta de NF-e emitida em V3 (CNPJ alfa) via endpoint V2 | 404 | 200 OK, response string |
Alguns pontos que costumam gerar dúvida:
- Chave de acesso (44 chars) — quando o emissor tem letras no CNPJ, a chave passa a usar Módulo 11 com ASCII−48. Você não precisa se preocupar com isso: a NFE.io gera a chave correta automaticamente.
- DANFE (PDF) — foi atualizado para imprimir o barcode da chave alfa. Se você só consome o PDF, não precisa mudar nada.
- GNRE (PE/ES) — sem nenhuma mudança de contrato para o cliente.
5.3 API de NFS-e
Endpoint base: https://api.nfe.io/v{version}/companies/{companyId}/serviceinvoices
| Cenário | V2 | V3 |
|---|---|---|
| Emissão de NFS-e com emissor numérico | ✅ normal | ✅ normal, response string |
| Emissão de NFS-e com emissor alfa | 400 Bad Request ("Use V3...") | ✅ depende da prefeitura aceitar (gate natural) |
| Consulta de NFS-e emitida em V3 alfa via V2 | 404 | 200 OK, response string |
Atenção, prefeituras: a adoção do CNPJ alfa varia bastante de um município para outro. Algumas prefeituras já atualizaram seus webservices; outras ainda não. A NFE.io não filtra essa resposta — manda a nota para a prefeitura e devolve exatamente o que ela responder. Se a prefeitura ainda rejeita, você recebe o erro como ele vem, sem mascaramento.
5.4 Distribuição de Documentos Fiscais (recebimento de DF-e)
Endpoint base: https://api.nfe.io/v{version}/dfe/inbound
| Cenário | V2 | V3 |
|---|---|---|
| Nota inbound recebida com CNPJ emissor numérico | ✅ entregue, number | ✅ entregue, string |
| Nota inbound recebida com CNPJ emissor alfa | 🔇 ignorada silenciosamente (não aparece no inbox V2) | ✅ entregue normalmente, string |
| Webhook de nota numérica | ✅ disparado, number | ✅ disparado, string |
| Webhook de nota alfa | 🚫 não disparado para subscribers V2 | ✅ disparado, string |
Vale tranquilizar: notas alfa não desaparecem. Elas existem no nosso sistema e ficam disponíveis para consumidores V3. Quando você quiser deixar de filtrá-las, basta migrar para a V3.
5.5 API de Consulta de Notas (consulta de NF-e)
Endpoint base: https://api.nfe.io/v{version}/lookup
| Cenário | V2 | V3 / V4 |
|---|---|---|
| Lookup por chave de acesso numérica | ✅ normal | ✅ normal |
| Lookup por chave alfa | 404 | 200 OK, response string |
| Scan / busca por CNPJ alfa | 404 | 200 OK |
6. Webhooks
6.1 Regra de envio
Aqui o critério é importante e às vezes contraintuitivo, então vale destacar:
O webhook segue a versão do contrato que o subscriber assinou — e não o valor do CNPJ da nota.
| Subscriber assinado em | CNPJ numérico | CNPJ alfanumérico |
|---|---|---|
| V2 | ✅ entregue, payload com federalTaxNumber: number | 🚫 não entregue |
| V3 | ✅ entregue, payload com federalTaxNumber: string | ✅ entregue, payload com federalTaxNumber: string |
6.2 Migração de webhook
A migração de webhook é tranquila e pode ser feita sem downtime:
- Cadastre uma nova subscription V3 apontando para um endpoint já preparado para receber
string. - Com as duas rodando em paralelo e a V3 confirmada, desligue a V2.
- Lembre-se: não há "duplicação" automática — se você mantiver as duas subscriptions ativas, vai receber o mesmo evento numérico nas duas versões.
6.3 Exemplo de payload — webhook V3
{
"event": "invoice.authorized",
"data": {
"id": "5f9...",
"issuer": {
"federalTaxNumber": "12ABC345000ABC", // string sempre
"name": "Empresa Nova Ltda."
},
"accessKey": "35260512ABC345000ABCxx...",
"status": "Authorized"
}
}
7. Códigos de status e mensagens de erro
7.1 Tabela canônica
Quando algo dá errado, a resposta é sempre clara sobre o motivo — nada de 500 genérico:
| Status | Quando ocorre | Mensagem típica |
|---|---|---|
400 Bad Request | Tentativa de emitir nota com CNPJ alfa em V2 (NF-e/NFC-e/NFS-e) | {"message":"Use V3 for alphanumeric CNPJ","code":"ALPHANUMERIC_CNPJ_REQUIRES_V3"} |
400 Bad Request | federalTaxNumber com formato inválido (tamanho ≠ 14, letras vedadas I/O/U/Q/F, DV inválido) | {"message":"Invalid federalTaxNumber"} |
404 Not Found | Consulta de entidade alfa via V1/V2 (API de Empresas, API de Consulta de Notas) | {"message":"Not Found"} |
cStat=215 (resposta SEFAZ) | XML chegou à SEFAZ, mas SEFAZ rejeitou (XSD antigo) | resposta real da SEFAZ, sem mascaramento NFE.io |
cStat=100 | SEFAZ aceitou (caminho feliz, alfa autorizado) | Autorizado o uso da NF-e |
7.2 O que não existe
Para evitar que você procure por algo que não vai encontrar:
- ❌ Não há
412 Precondition Failed— não usamos esse código para isto. - ❌ Não há feature flag de "habilitar CNPJ alfa para minha conta".
- ❌ Não há whitelist por AccountId.
8. Checklist de preparação
8.1 Para quem só usa CNPJ numérico
A boa notícia: é uma lista curtíssima.
- Documentar internamente que
federalTaxNumberem V2 continuanumber— nada precisa mudar. - Treinar suporte/atendimento: quando um cliente final pedir suporte a CNPJ alfa, direcionar para a migração V3.
8.2 Para quem vai suportar CNPJ alfanumérico
Aqui vale ser metódico. Separamos por frente para você não esquecer nenhum ponto.
Código
- Tipo de
federalTaxNumberem modelos / DTOs / entities →string(nãolong, nãoint64, nãobigint). - Validação de formato → aceita
[A-HJ-NPRT-Z0-9]{12}[0-9]{2}ou usar a lib oficial da sua linguagem para CNPJ. - Validação de DV → Módulo 11 com ASCII−48.
- Remover qualquer
Long.parseLong(cnpj),int64(cnpj),cnpj.toFixed(0),cnpj.padStart(14, '0')aplicado antes de saber se é numérico. - Trocar máscara de display de
"00.000.000/0000-00"para algo tolerante a letras (ou exibir sem máscara).
Banco de dados
- Coluna
cnpj/federal_tax_number→VARCHAR(14)(nãoBIGINT, nãoNUMERIC(14)). - Índices de igualdade → continuam funcionando, mas revise índices que dependiam de ordenação numérica.
- Considere
COLLATEou normalização paraUPPERno armazenamento (CNPJs alfa são[A-Z], mas inputs podem vir minúsculos).
Integração
- Trocar endpoint
/v2/...por/v3/...no fluxo onde precisar. - Atualizar a webhook subscription para V3.
- Atualizar parsers JSON para esperar
string(a maioria das libs lida nativamente, mas linguagens de tipagem forte podem precisar de cast). - Logs / observabilidade → garantir que o CNPJ não está sendo serializado como número em algum sink (ex.: mapping do Elasticsearch).
Teste
- Cenário positivo numérico em V3.
- Cenário positivo alfa em V3.
- Cenário V2 com payload
stringcontendo letras → confirmar400. - Cenário V2 com
GETde empresa alfa → confirmar404. - Webhook V3 com CNPJ alfa → confirmar entrega e parse.
9. Cenários de teste em homologação
A SEFAZ disponibiliza CNPJs alfanuméricos de teste no ambiente de homologação desde 06/04/2026 — use-os para validar a integração de ponta a ponta antes de julho.
9.1 Exemplos didáticos (não reais — substitua pelos publicados pela Receita)
CNPJ alfa de homologação: 12ABC345000ABC
CNPJ numérico de homologação: 12345678000199
9.2 Fluxo recomendado
Um roteiro que cobre os principais caminhos:
- Cadastre a empresa alfa via
POST /v3/companies(homologação). - Tente emitir uma NF-e/NFS-e de teste pela V3.
- Observe a resposta da SEFAZ:
cStat=100→ autorizada (caminho feliz, alfa funcionando).cStat=215ou similar → SEFAZ ainda não liberou (esperado em alguns períodos).
- Confira o webhook V3 chegando com
string. - Por fim, tente a mesma operação via V2 → confirme os
400/404esperados.
10. Perguntas frequentes
P1. Vocês vão descontinuar a V2? Não por causa dessa mudança. A V2 continua suportada por tempo indeterminado, com o contrato congelado. Se houver depreciação no futuro, ela será comunicada com antecedência pelos canais oficiais.
P2. Preciso pedir liberação para emitir com CNPJ alfa? Não. Não existe whitelist, feature flag nem aprovação manual. Quando você usa a V3 com CNPJ alfa, a requisição vai até a SEFAZ/prefeitura, e a emissão só funciona se a autoridade aceitar.
P3. O que acontece se eu mandar uma string "12345678000199" (numérico, mas como texto) na V3?
Funciona normalmente. A V3 aceita os dois tipos na entrada — numérico ou alfanumérico, como string ou number.
P4. E se eu mandar number na V2 com um CNPJ que deveria existir como alfa?
JSON number não consegue representar letras. Se você tentar mandar "12ABC345000ABC" em V2 (que espera número), a request falha no parser/validador → 400 Bad Request.
P5. Os CNPJs numéricos atuais vão virar alfa em algum momento? Não. CNPJs já emitidos pela Receita Federal continuam numéricos. Só os novos cadastros (a partir de julho/2026) é que podem vir alfanuméricos.
P6. Como sei se um CNPJ é alfa ou numérico programaticamente?
Verifique se há algum caractere fora do conjunto [0-9] nas 12 primeiras posições. Se houver, é alfa. Os 2 dígitos finais (DV) são sempre numéricos.
function isAlphanumericCnpj(cnpj) {
return /[A-Z]/.test(cnpj.substring(0, 12));
}
P7. O DANFE / PDF da nota vai mudar? Internamente, sim — o barcode da chave de acesso passa a aceitar caracteres alfanuméricos (CODE-128A). Visualmente, o layout permanece o mesmo. Se você consome o PDF, nada muda no seu lado.
P8. E o cliente que tem rotina de batch processando milhares de notas?
Comece fazendo um inventário dos pontos onde federalTaxNumber é parseado. Migre o tipo e os parsers para string e rode tudo em homologação antes de subir para produção. Nossa recomendação é migrar de forma incremental: comece pelo fluxo de consulta (o mais barato), depois cadastro e, por último, emissão.
P9. E os meus dados históricos com CNPJ numérico no Mongo/Postgres?
Eles permanecem como estão. A NFE.io não exige reescrita dos dados antigos. Internamente, lemos o campo de forma polimórfica (number ou string) e sempre o expomos como string na V3.
P10. Onde abrir dúvidas?
- Suporte técnico: portal de integradores NFE.io.
- Documentação pública: https://nfe.io/docs.
- Fontes regulatórias oficiais: IN RFB 2.229/2024 e NT Conjunta ENCAT 2025.001 v1.00.
Resumo técnico em 3 linhas:
- Trate
federalTaxNumbercomostringem qualquer integração nova.- Use endpoints
/v3/para consumir/produzir CNPJ alfa.- Não invente whitelist nem flag — a SEFAZ é o único gate real.