---
title: "CNPJ Alfanumérico — Documentação Técnica"
description: "Guia técnico para desenvolvedores e arquitetos: contratos JSON antes/depois, comportamento por produto, webhooks, códigos de status e checklist de migração para o CNPJ alfanumérico."
source_url: https://nfe.io/docs/release-notes/2026-3-cnpj-alfanumerico/documentacao-tecnica
last_updated: 2026-07-03
---

# CNPJ Alfanumérico — Documentação Técnica

Este guia é o companheiro técnico do [Comunicado](/docs/release-notes/2026-3-cnpj-alfanumerico). 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

1. [Visão geral em 30 segundos](#1-visão-geral-em-30-segundos)
2. [O novo formato do CNPJ](#2-o-novo-formato-do-cnpj)
3. [O princípio de versionamento da NFE.io](#3-o-princípio-de-versionamento-da-nfeio)
4. [O que muda no contrato da API](#4-o-que-muda-no-contrato-da-api)
5. [Mudanças por produto](#5-mudanças-por-produto)
6. [Webhooks](#6-webhooks)
7. [Códigos de status e mensagens de erro](#7-códigos-de-status-e-mensagens-de-erro)
8. [Checklist de preparação](#8-checklist-de-preparação)
9. [Cenários de teste em homologação](#9-cenários-de-teste-em-homologação)
10. [Perguntas frequentes](#10-perguntas-frequentes)

---

## 1. Visão geral em 30 segundos

A partir de 01/08/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 um **novo versionamento** das APIs, com uma regra simples de entender:

| Versão | Status | Tipo de `federalTaxNumber` na request | Tipo na response/webhook |
|---|---|---|---|
| Versionamento atual (v1) | congelada | `number` | `number` |
| Versionamento atual (v2) | congelada (boundary defensivo) | `number` | `number` |
| **Novo versionamento** | **novo** | `string` (aceita `number` por compatibilidade na entrada) | **sempre `string`** |

> Cada produto tem o seu **próprio** novo versionamento — o número da versão pode variar entre produtos (emissão, cadastro, distribuição e cada consulta evoluem em ritmos diferentes).

Se você guardar só uma frase deste documento, que seja esta:

> **Mantra:** *"O versionamento atual nunca enxerga CNPJ alfa. O novo versionamento é 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:

```text
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 das APIs de **emissão, cadastro e distribuição**. A leitura é direta: na coluna legado, o sistema **protege** você do formato novo; na coluna do novo versionamento, ele o **entrega** de forma consistente.

| Camada | Versionamento atual | Novo versionamento (alfa-aware) |
|---|---|---|
| API de Empresas (cadastro) | empresa alfa → **400 Bad Request** (requer o novo versionamento) | 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) | `federalTaxNumber` tratado como **texto**; visibilidade segue a versão da assinatura | documento alfa entregue como `string` |
| Webhook | **formato do payload** segue a versão da assinatura/webhook | entregue como `string` |
| Response JSON | **sempre `number`** | **sempre `string`** |

#### Consultas — trilha própria de versionamento

As **APIs de Consulta** seguem em trilha separada das de emissão. O **versionamento ainda está em estudo**, voltado à **compatibilização entre as versões** existentes. Hoje, em homologação, o CNPJ alfanumérico está disponível **apenas para teste** — porém **vamos trabalhar em um versionamento próprio para essa alteração** (uma versão alfa-aware dedicada às Consultas), que será comunicado quando definido. O contrato pretendido: a **versão atual** recusa CNPJ alfa (`400`) e o **novo versionamento** entrega o dado (`200`) ou `404` se não existir. Detalhes e roadmap em [Consultas](/release-notes/2026-3-cnpj-alfanumerico/consultas).

| Camada | Versionamento atual | Versão alfa-aware |
|---|---|---|
| API de Consulta de Notas | CNPJ alfa → **400 Bad Request** | `200 OK` (`string`); **`404`** se o registro não existir |
| API de Consulta de Pessoa Jurídica (CNPJ) | CNPJ alfa → **400 Bad Request** | `200 OK` (`string`); **`404`** se o registro não existir |

### 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:

1. **Zero regressão.** Para clientes nas suas versões atuais, nada muda — nem no schema, nem no tipo do campo, nem no comportamento. Quem está integrado hoje pode ignorar tranquilamente toda essa mudança.
2. **Sem flags, sem espera.** Não existe feature flag, whitelist nem código `412` para "habilitar" o alfa. Quem decide quando o alfa entra em produção é a **origem do dado** (a SEFAZ, na NF-e/NFC-e; as prefeituras, na NFS-e): no instante em que ela libera o formato alfa, o sistema NFE.io passa a autorizar automaticamente (ex.: `cStat=100` na NF-e), sem nenhuma intervenção manual da nossa parte.
3. **Determinístico.** O novo versionamento 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 — o novo versionamento aceita os dois tipos

Para facilitar a sua vida na migração, o novo versionamento é flexível na entrada: ele 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`.

> Os valores de `federalTaxNumber` nos exemplos abaixo são **ilustrativos** — não são CNPJs reais.

```jsonc
// ✅ Recomendado (novo versionamento)
{
  "federalTaxNumber": "12ABC345000ABC"
}

// ✅ Também aceito (novo versionamento, compat — para CNPJ numérico)
{
  "federalTaxNumber": 12345678000199
}

// ❌ Versionamento atual rejeita string com letras
{
  "federalTaxNumber": "12ABC345000ABC"  // → 400 Bad Request
}
```

### 4.2 Response — novo versionamento sempre string

Na saída, o novo versionamento é rígido 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.

> Os valores de `federalTaxNumber` nos exemplos abaixo são **ilustrativos** — não são CNPJs reais.

```jsonc
// Versionamento atual (hoje e amanhã — congelada)
{
  "id": "...",
  "federalTaxNumber": 12345678000199,    // number
  "name": "Empresa Exemplo S.A."
}

// Novo versionamento — CNPJ numérico
{
  "id": "...",
  "federalTaxNumber": "12345678000199",  // string
  "name": "Empresa Exemplo S.A."
}

// Novo versionamento — CNPJ alfanumérico
{
  "id": "...",
  "federalTaxNumber": "12ABC345000ABC",  // string
  "name": "Empresa Nova Ltda."
}
```

### 4.3 Selecionando a versão

A versão é escolhida **pelo endpoint** — o segmento de versão fica na URL (ex.: `/v{versão}/...`). **Não há versionamento por header**: o número da versão está sempre no caminho da chamada.

**O número da versão varia por produto** — cada API tem a sua *versão atual* (numérica, congelada) e a sua *versão alfa-aware* (o novo versionamento), e essas numerações **não são iguais entre os produtos**. Consulte a numeração de cada um nos guias [Emissões / DF-e](/release-notes/2026-3-cnpj-alfanumerico/emissoes-dfe) e [Consultas](/release-notes/2026-3-cnpj-alfanumerico/consultas).

---

## 5. Mudanças por produto

O comportamento detalhado por produto está organizado em dois guias:

- **[Emissões / DF-e](/release-notes/2026-3-cnpj-alfanumerico/emissoes-dfe)** — cadastro de empresas, NF-e/NFC-e, NFS-e e Distribuição de DF-e.
- **[Consultas](/release-notes/2026-3-cnpj-alfanumerico/consultas)** — Consulta de Notas (NF-e) e Consulta de Pessoa Jurídica (CNPJ / legalentities).

---

## 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 |
|---|---|---|
| **Versionamento atual** | ✅ entregue, payload com `federalTaxNumber: number` | 🚫 **não entregue** |
| **Novo versionamento** | ✅ 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:

1. Cadastre uma **nova subscription no novo versionamento** apontando para um endpoint já preparado para receber `string`.
2. Com as duas rodando em paralelo e o novo versionamento confirmado, **desligue o versionamento atual**.
3. 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 do novo versionamento

```jsonc
{
  "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

:::info Esta seção cobre as APIs de **emissão**
Os códigos e mensagens abaixo descrevem o comportamento das APIs de **emissão** (NF-e/NFC-e/NFS-e, cadastro e distribuição). O comportamento de erro das **Consultas** está no guia [Consultas](/release-notes/2026-3-cnpj-alfanumerico/consultas).
:::

### 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` / rejeição | Tentativa de emitir com CNPJ alfa na versão atual | a versão atual rejeita; o erro orienta o novo versionamento. **O formato varia por produto** — ex.: NFS-e devolve texto orientando a v3; na NF-e/NFC-e a emissão na versão atual não resolve a empresa alfa |
| `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, via versão atual, de uma **nota emitida no novo versionamento** (CNPJ alfa) | `{"message":"Not Found"}` |
| `cStat=215` (resposta SEFAZ — **NF-e/NFC-e**) | XML chegou à SEFAZ, mas SEFAZ rejeitou (XSD antigo) | resposta real da SEFAZ, sem mascaramento NFE.io |
| `cStat=100` (**NF-e/NFC-e**) | 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 **`federalTaxNumber` no versionamento atual continua `number`** — nada precisa mudar.
- [ ] Treinar suporte/atendimento: quando um cliente final pedir suporte a CNPJ alfa, **direcionar para a migração ao novo versionamento do produto utilizado**.

### 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 `federalTaxNumber` em modelos / DTOs / entities → `string` (não `long`, `int64`, `bigint`, etc. — qualquer tipo de armazenamento numérico).
- [ ] 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

- [ ] **Analise como o `federalTaxNumber` é armazenado** no seu banco: se hoje é um tipo numérico (ex.: `BIGINT`, `NUMERIC(14)`), será necessário acomodar texto (ex.: `VARCHAR(14)` ou equivalente). A decisão de modelagem é sua.
- [ ] Índices de igualdade → continuam funcionando, mas **revise índices que dependiam de ordenação numérica**.
- [ ] Considere `COLLATE` ou normalização para `UPPER` no armazenamento (CNPJs alfa são `[A-Z]`, mas inputs podem vir minúsculos).

#### Integração

- [ ] Trocar o endpoint da **versão atual** pelo do **novo versionamento** do produto que você usa (o número da versão varia por produto).
- [ ] Atualizar a webhook subscription para o novo versionamento.
- [ ] 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 no novo versionamento.
- [ ] Cenário positivo alfa no novo versionamento.
- [ ] Cenário no versionamento atual com payload `string` contendo letras → confirmar `400`.
- [ ] Cenário no versionamento atual com `GET` de empresa alfa → confirmar `400`.
- [ ] Webhook do novo versionamento com CNPJ alfa → confirmar entrega e parse.

---

## 9. Cenários de teste em homologação

A **Sefaz / Emissor Nacional** disponibilizam CNPJs alfanuméricos de teste no ambiente de homologação **a partir de junho/2026 (sem data definida)** — use-os para validar a integração de ponta a ponta antes de **01/08/2026**.

### 9.1 Exemplos didáticos (não reais — substitua pelos publicados pela Receita)

```text
CNPJ alfa de homologação:         12ABC345000ABC
CNPJ numérico de homologação:     12345678000199
```

### 9.2 Fluxo recomendado

Um roteiro que cobre os principais caminhos:

1. Cadastre a empresa alfa via `POST /v3/companies` (homologação).
2. Tente emitir uma NF-e/NFS-e de teste pelo novo versionamento.
3. Observe a resposta da **origem do dado** (na NF-e/NFC-e, via `cStat` da SEFAZ; na NFS-e, conforme a prefeitura):
   - autorizada (ex.: `cStat=100` na NF-e) → caminho feliz, alfa funcionando.
   - rejeitada (ex.: `cStat=215` na NF-e) → a autoridade ainda não liberou o formato alfa (esperado em alguns períodos).
4. Confira o webhook do novo versionamento chegando com `string`.
5. Por fim, tente a mesma operação via versionamento atual → confirme os `400`/`404` esperados.

---

## 10. Perguntas frequentes

**P1. Vocês vão descontinuar o versionamento atual?**
Não por causa dessa mudança. O versionamento atual continua suportado 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 o novo versionamento 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) no novo versionamento?**
Funciona normalmente. O novo versionamento aceita os dois tipos na entrada — numérico ou alfanumérico, como `string` ou `number`.

**P4. E se eu mandar `number` no versionamento atual com um CNPJ que deveria existir como alfa?**
JSON `number` não consegue representar letras. Se você tentar mandar `"12ABC345000ABC"` no versionamento atual (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 01/08/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.

```js
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` no novo versionamento.

**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:**
>
> 1. Trate `federalTaxNumber` como `string` em qualquer integração nova.
> 2. Use o **novo versionamento** de cada produto para consumir/produzir CNPJ alfa (o número da versão varia por produto).
> 3. Não invente whitelist nem flag — a origem do dado (SEFAZ/prefeitura) é o único gate real.
