Chave de Acesso da NF-e: Como Validar e Consultar por API

Desenvolvedor analisando a chave de acesso de uma NF-e na tela do computador

Toda NF-e autorizada no Brasil carrega uma chave de acesso de 44 posições. É ela que o seu sistema usa para achar a nota na SEFAZ (a Secretaria da Fazenda que autoriza a nota), conferir se foi cancelada ou, quando você participa da operação, baixar o XML. Parece só um número comprido, mas cada trecho tem significado, do estado ao dígito verificador. Quem entende essa estrutura valida a chave de acesso localmente em microssegundos e só gasta requisição com chaves bem formadas.

Os 44 dígitos da chave de acesso da NF-e

A chave de acesso é a concatenação de nove campos da própria nota. O Manual de Orientação do Contribuinte (MOC), publicado na seção de manuais do Portal da NF-e, define a ordem e o tamanho de cada um. A mesma estrutura vale para a NF-e (modelo 55) e para a NFC-e (modelo 65, a nota de consumidor do varejo). Por isso, um único validador atende as duas.

Campo Posições Dígitos O que guarda Exemplo
cUF 1 a 2 2 Código IBGE da UF do emitente 35 (SP)
AAMM 3 a 6 4 Ano e mês de emissão 2609
CNPJ ou CPF 7 a 20 14 Documento do emitente 11222333000181
mod 21 a 22 2 Modelo do documento 55
serie 23 a 25 3 Série da nota 001
nNF 26 a 34 9 Número da nota 000012345
tpEmis 35 1 Forma de emissão 1 (normal)
cNF 36 a 43 8 Código numérico aleatório 48213075
cDV 44 1 Dígito verificador 5

Juntando a última coluna, sai a chave de acesso fictícia usada nos exemplos: 35260911222333000181550010000123451482130755.

Diagrama da estrutura da chave de acesso da NF-e com os nove campos e a quantidade de dígitos de cada um

UF, data e emitente

Os dois primeiros dígitos seguem a tabela de UF do IBGE: 35 é São Paulo, 31 é Minas Gerais, 43 é Rio Grande do Sul. Só existem 27 códigos válidos, e qualquer outro valor indica uma chave de acesso corrompida.

O AAMM traz ano e mês da emissão (2609 para setembro de 2026), e o mês precisa estar entre 01 e 12.

As 14 posições seguintes guardam o CNPJ do emitente. Quando o emitente é pessoa física, como o produtor rural em alguns estados, o CPF ocupa o campo, completado com zeros à esquerda. Por isso, o validador não pode assumir que aquele trecho sempre é um CNPJ.

Modelo, série e número

O modelo 55 é NF-e, e o 65, NFC-e. A série tem três dígitos, de 000 a 999, e o número da nota tem nove, com zeros à esquerda. Juntos, CNPJ, modelo, série e número apontam uma única nota daquele emitente.

Forma de emissão, código numérico e DV

O tpEmis indica se a nota saiu em emissão normal (1), no Regime Especial da Nota Fiscal Fácil (3) ou em contingência, o modo usado quando a SEFAZ está fora do ar: FS-IA (2), EPEC (4), FS-DA (5), SVC-AN (6), SVC-RS (7) ou a contingência off-line da NFC-e (9). O valor 8 não é usado na NF-e. Reemitir a nota em outra forma de emissão muda a chave de acesso.

O cNF é um código de oito dígitos que o sistema emissor gera ao acaso, para que ninguém deduza chaves de terceiros só incrementando o número da nota. Gerá-lo em sequência anula essa proteção. Por fim, o DV protege a chave de acesso contra erro de digitação.

Na prática: a chave de acesso já traz UF, mês, emitente e modelo. Antes de qualquer chamada de rede, seu código consegue responder se a nota é de São Paulo, se é NFC-e e se o CNPJ bate com o fornecedor esperado.

Dígito verificador NF-e: cálculo pelo módulo 11

O dígito verificador da chave de acesso usa módulo 11 (o resto da divisão por 11), com pesos de 2 a 9. O erro mais comum é aplicar os pesos da esquerda para a direita.

O passo a passo do cálculo

  1. Pegue os 43 primeiros caracteres da chave.
  2. Percorra da direita para a esquerda, multiplicando cada dígito pelos pesos 2, 3, 4, 5, 6, 7, 8, 9 e recomeçando em 2 depois do 9.
  3. Some todos os produtos.
  4. Calcule o resto da divisão da soma por 11.
  5. Se o resto for 0 ou 1, o DV é 0. Caso contrário, o DV é 11 menos o resto.

No nosso exemplo, a soma ponderada dá 589. 589 dividido por 11 deixa resto 6, e o DV é 11 menos 6, ou seja, 5, o último dígito da chave.

Código em Python

A função abaixo já está pronta para o CNPJ alfanumérico e para o prefixo NFe do XML, dois pontos detalhados na próxima seção. Em vez de int(ch), ela usa o código ASCII do caractere menos 48. Como 48 é o código do “0”, os dígitos continuam valendo 0 a 9, e as letras seguem a regra da Nota Técnica.

import re

UFS = {"11", "12", "13", "14", "15", "16", "17", "21", "22", "23", "24",
       "25", "26", "27", "28", "29", "31", "32", "33", "35", "41", "42",
       "43", "50", "51", "52", "53"}

def calcular_dv(base43):
    soma, peso = 0, 2
    for ch in reversed(base43):
        soma += (ord(ch) - 48) * peso
        peso = 2 if peso == 9 else peso + 1
    resto = soma % 11
    return 0 if resto < 2 else 11 - resto

def normalizar_chave(entrada):
    s = str(entrada).strip().upper()
    if s.startswith("NFE"):          # atributo Id do XML: "NFe" + chave
        s = s[3:]
    return re.sub(r"[^0-9A-Z]", "", s)

def valida_chave(chave):
    # 6 dígitos (UF + AAMM), 12 que aceitam letra (raiz e ordem do CNPJ), 26 dígitos
    if not re.fullmatch(r"[0-9]{6}[A-Z0-9]{12}[0-9]{26}", chave):
        return False
    if chave[:2] not in UFS or not 1 <= int(chave[4:6]) <= 12:
        return False
    if chave[20:22] not in ("55", "65"):
        return False
    return calcular_dv(chave[:43]) == int(chave[43])

print(valida_chave(normalizar_chave("3526 0911 2223 3300 0181 5500 1000 0123 4514 8213 0755")))  # True

Programador escrevendo a função que valida o dígito verificador da NF-e

Código em JavaScript

A versão em Node faz as mesmas checagens, confere também a forma de emissão (tpEmis) e devolve o motivo da recusa, útil para a mensagem ao usuário.

const UFS = new Set(['11','12','13','14','15','16','17','21','22','23','24','25','26','27','28','29','31','32','33','35','41','42','43','50','51','52','53']);
const TP_EMIS = new Set(['1','2','3','4','5','6','7','9']);

function normalizarChave(entrada) {
  let s = String(entrada).trim().toUpperCase();
  if (s.startsWith('NFE')) s = s.slice(3);
  return s.replace(/[^0-9A-Z]/g, '');
}

function dvChave(base43) {
  let soma = 0, peso = 2;
  for (let i = base43.length - 1; i >= 0; i--) {
    soma += (base43.charCodeAt(i) - 48) * peso;
    peso = peso === 9 ? 2 : peso + 1;
  }
  const resto = soma % 11;
  return resto < 2 ? 0 : 11 - resto;
}

function validarChave(entrada) {
  const chave = normalizarChave(entrada);
  if (!/^[0-9]{6}[A-Z0-9]{12}[0-9]{26}$/.test(chave)) return { ok: false, erro: 'formato' };
  if (!UFS.has(chave.slice(0, 2))) return { ok: false, erro: 'cUF' };
  const mes = Number(chave.slice(4, 6));
  if (mes < 1 || mes > 12) return { ok: false, erro: 'AAMM' };
  const modelo = chave.slice(20, 22);
  if (modelo !== '55' && modelo !== '65') return { ok: false, erro: 'modelo' };
  if (!TP_EMIS.has(chave[34])) return { ok: false, erro: 'tpEmis' };
  if (dvChave(chave.slice(0, 43)) !== Number(chave[43])) return { ok: false, erro: 'DV' };
  return { ok: true, chave, modelo: modelo === '55' ? 'NF-e' : 'NFC-e' };
}

Com as duas funções prontas, sobram as armadilhas da entrada real e, depois, a consulta de verdade. Se você quer os dados completos da nota sem resolver captcha, a API de consulta NF-e do Hub do Desenvolvedor devolve o resultado em JSON ou XML. Dá para testar grátis antes de colocar em produção.

Como validar chave de acesso NF-e antes de consultar

Validar a chave de acesso localmente é o filtro mais barato do pipeline: barra erro de digitação, lixo de planilha e chave truncada antes que virem requisição. A regra de ouro é normalizar primeiro e validar depois.

Máscara, espaços e o prefixo NFe

No DANFE (a versão impressa da nota), ela aparece em 11 grupos de quatro dígitos separados por espaço. Em planilha, às vezes vem com ponto ou traço. No XML autorizado, o atributo Id da tag infNFe tem 47 caracteres, porque traz o prefixo NFe antes dos 44 dígitos.

Por isso, as funções acima removem o prefixo e depois descartam tudo que não é letra ou número. As letras ficam, porque com o CNPJ alfanumérico apagá-las corromperia uma chave válida.

Excel e LibreOffice convertem sequências longas de dígitos em notação científica e guardam só 15 dígitos significativos. Os demais viram zero. Importe a coluna como texto, sempre.

CNPJ alfanumérico dentro da chave de acesso

A Receita Federal mudou a regra de formação do CNPJ pela Instrução Normativa RFB 2.229/2024, e a página oficial do CNPJ alfanumérico explica o novo formato. As oito posições da raiz e as quatro da ordem passam a aceitar letras maiúsculas e números. Os dois dígitos verificadores continuam numéricos, e os CNPJs já existentes não mudam.

Como o CNPJ ocupa as posições 7 a 20, a chave de acesso também muda. A Nota Técnica Conjunta 2025.001, publicada no Portal da NF-e, define três pontos que afetam o seu código:

  • A chave continua com 44 posições, e a expressão regular passa a ser [0-9]{6}[A-Z0-9]{12}[0-9]{26}. Só as 12 primeiras posições do CNPJ aceitam letra.
  • O cálculo do DV troca cada caractere pelo seu código ASCII menos 48 antes do módulo 11. Dessa forma, “0” a “9” continuam valendo 0 a 9, “A” (ASCII 65) vale 17, “B” vale 18 e assim por diante.
  • O código de barras do DANFE, em CODE-128C, só aceita números, e a NT sugere alternar para o CODE-128A quando aparecem letras.

Para NF-e e NFC-e, a NT 2026.004, que complementa a Conjunta com os schemas, pôs a mudança em produção em 01/07/2026. Ou seja, seu sistema já precisa aceitar essas chaves. Um exemplo fictício, com o CNPJ de demonstração 12ABC34501DE35, fica assim: 35260912ABC34501DE35550010000123451482130756. As funções acima validam essa chave sem adaptação.

Se o seu validador também confere o CNPJ extraído da chave, ele precisa seguir a mesma regra do ASCII menos 48. Com emitente pessoa física, esse trecho é 000 seguido do CPF, e aí a validação é a de CPF. O post sobre como validar um CNPJ, inclusive o alfanumérico traz esse algoritmo em detalhe.

Atenção: guardar a chave de acesso em coluna BIGINT ou NUMERIC quebra com o CNPJ alfanumérico. Use CHAR(44) ou VARCHAR(44). Mesmo sem letras, guardar como número já apagava os zeros à esquerda.

NF-e ou NFC-e: o modelo muda o caminho

Uma chave de acesso com modelo 65 passa no mesmo cálculo de DV, mas nem todo serviço de consulta trata os dois modelos da mesma forma. Em muitos estados, a NFC-e tem portal próprio, consultado por QR Code. Ler as posições 21 e 22 e rotear a consulta para o serviço certo evita um falso “nota não encontrada”.

Chave válida não significa nota autorizada

O DV só prova que a sequência foi montada de forma consistente. Qualquer pessoa gera uma chave de acesso matematicamente perfeita para uma nota que nunca existiu. Por isso, a validação local serve de filtro, e a resposta final sobre a nota vem sempre da consulta.

A consulta pode trazer situações diferentes de “autorizada”:

  • Cancelada: a nota foi autorizada e depois recebeu evento de cancelamento. A chave continua existindo, mas a operação não vale.
  • Denegada: a SEFAZ registrou a nota e negou o uso por irregularidade fiscal do emitente ou do destinatário. Aquele número não pode ser reaproveitado em outra nota.
  • Não encontrada: a chave não consta na base consultada. Pode ser erro, nota ainda em processamento ou chave inventada.
Situação Sintoma O que fazer
Chave com espaços ou pontos Erro de formato com 44 dígitos corretos Normalizar antes de validar
Id do XML colado inteiro 47 caracteres começando com NFe Remover o prefixo NFe
Dígito trocado DV não confere Pedir a chave de novo, sem consultar
Dígito faltando Erro de formato com 43 caracteres Pedir a chave de novo, sem consultar
Chave vinda do Excel Final da chave zerado Importar a coluna como texto
Modelo 65 no serviço de NF-e Nota não encontrada Rotear pelo modelo
Nota cancelada Evento de cancelamento na resposta Bloquear a entrada no ERP
Nota denegada Uso denegado Tratar como nota sem validade

O outro lado, quando a sua própria nota volta recusada, está no artigo sobre como evitar rejeições na emissão de NF-e.

Documento fiscal impresso com código de barras sobre a mesa, ao lado de notebook e celular

Consulta NF-e por chave de acesso: portal, webservice ou API

Validada, a chave de acesso pode seguir por três caminhos, com custos bem diferentes.

Portal da NF-e

O caminho manual é o Consultar NF-e do Portal Nacional. Você cola a chave, resolve o captcha e vê o resumo. Para a versão completa, o portal exige certificado digital. Serve para conferência pontual, não para integração.

Webservice da SEFAZ

O serviço oficial de consulta de protocolo recebe a chave e responde com o código de situação (cStat), o protocolo e os eventos vinculados. Para usá-lo, você precisa de certificado digital ICP-Brasil, conexão com autenticação mútua, montagem de envelope SOAP e um mapa dos endereços de cada autorizador. O XML completo vem por outro serviço, a distribuição de DF-e (documentos fiscais eletrônicos), disponível apenas para quem participa da operação, como o destinatário.

As situações vistas acima chegam do webservice como códigos, e alguns aparecem o tempo todo:

  • 100 e 150: autorizado o uso da NF-e (o 150 indica autorização fora de prazo).
  • 101: cancelamento homologado.
  • 110, 301, 302 e 303: uso denegado.
  • 217: a nota não consta na base de dados da SEFAZ.
  • 656: consumo indevido, bloqueio temporário de quem repete consultas demais.

Quem reconsulta a mesma chave de acesso em loop recebe o 656 e fica um tempo sem resposta para todas as notas, não só para a problemática.

API de consulta

Uma API NF-e de terceiros esconde essa infraestrutura atrás de uma chamada HTTP. Você manda a chave de acesso e recebe o resultado em JSON ou XML, sem captcha.

Critério Portal da NF-e Webservice SEFAZ API de consulta
Captcha Sim Não Não
Certificado digital Na consulta completa Sempre Depende do fornecedor
Formato Página HTML SOAP e XML JSON ou XML
Automação Não é o objetivo Sim, com esforço Sim
Esforço inicial Nenhum Alto Baixo

Na API, os erros chegam no status HTTP, além do corpo da resposta. 4xx indica problema na sua requisição, e repetir não resolve. 5xx indica falha do servidor e pede nova tentativa. O guia de HTTP status codes para APIs ajuda a montar essa regra.

Quer testar com as suas próprias chaves? A consulta de NF-e por API do Hub entra no mesmo plano que os webservices de CPF, CNPJ, CEP e frete, e você pode fazer chamadas de quantos IPs precisar. Crie a conta de teste e use o validador deste artigo como filtro antes de cada chamada.

Consulta em lote com cache e idempotência

O cenário típico é a conciliação de uma planilha com 3 mil notas. Um loop que chama a API linha a linha desperdiça consultas com chaves duplicadas, chaves inválidas e notas que você consultou ontem.

A abordagem que funciona tem quatro etapas:

  1. Normalizar e validar cada entrada, separando as inválidas num relatório próprio.
  2. Deduplicar, porque a mesma chave aparece várias vezes em planilhas reais.
  3. Buscar no cache antes de ir à rede.
  4. Consultar em ritmo constante, sem rajadas (é o que evita o 656), gravando o resultado no cache.

Fluxo de consulta em lote por chave de acesso com validação, deduplicação, cache e chamada à API

O código abaixo reaproveita normalizar_chave e valida_chave do exemplo em Python. Endereço e autenticação são ilustrativos: confira os valores reais no painel do Hub. Se a base mistura NF-e e NFC-e, separe as chaves pelo modelo antes do laço e chame o serviço certo para cada grupo.

import time
import requests

URL_DA_API = "https://URL_DA_API/nfe"   # ilustrativo: confira no painel do Hub
TOKEN = "SEU_TOKEN"
TTL_RECENTE = 3600           # mês atual ou anterior: ainda pode ser cancelada
TTL_ANTIGA = 7 * 24 * 3600   # nota mais antiga muda pouco

cache = {}   # em produção, use Redis ou uma tabela

def meses_recentes():
    agora = time.localtime()
    ano, mes = agora.tm_year, agora.tm_mon - 1
    if mes == 0:
        ano, mes = ano - 1, 12
    return {time.strftime("%y%m", agora), f"{ano % 100:02d}{mes:02d}"}

def ttl_para(chave):
    return TTL_RECENTE if chave[2:6] in meses_recentes() else TTL_ANTIGA

def consultar(chave, sessao):
    """Devolve (dados, foi_a_rede)."""
    item = cache.get(chave)
    if item and time.time() < item["expira"]:
        return item["dados"], False
    resp = sessao.get(URL_DA_API, params={"chave": chave, "token": TOKEN}, timeout=15)
    resp.raise_for_status()
    dados = resp.json()
    cache[chave] = {"dados": dados, "expira": time.time() + ttl_para(chave)}
    return dados, True

def consultar_lote(entradas):
    validas, invalidas = {}, []
    for entrada in entradas:
        chave = normalizar_chave(entrada)
        if valida_chave(chave):
            validas[chave] = None    # dict remove duplicadas e mantém a ordem
        else:
            invalidas.append(entrada)
    resultados = {}
    with requests.Session() as sessao:
        for chave in validas:
            resultados[chave], foi_a_rede = consultar(chave, sessao)
            if foi_a_rede:
                time.sleep(0.5)      # pausa só quando saiu para a rede
    return resultados, invalidas

O TTL (o tempo de validade no cache) vem do AAMM da chave. Como o AAMM não traz o dia, notas do mês corrente e do anterior contam como recentes, porque uma nota do dia 30 ainda pode ser cancelada no dia 1º, e ficam pouco no cache. As mais antigas raramente mudam de situação e ficam mais. No exemplo, qualquer erro HTTP interrompe o lote. Em produção, capture a exceção por chave, registre as falhas 4xx como definitivas e recoloque as 5xx numa fila de nova tentativa. Expiração e invalidação estão no texto sobre o que é cache e suas estratégias.

Dica: use a própria chave de acesso como chave de idempotência. Com o cache em Redis ou numa tabela, se o job cair no meio e for reiniciado, a nota já gravada não gera nova consulta nem registro duplicado no ERP.

A chave de acesso é naturalmente única, e isso a torna perfeita para UPSERT (inserir ou atualizar) e para restrição de unicidade no banco. O artigo sobre idempotência em APIs e como evitar registros duplicados mostra o padrão completo para quem recebe as notas por webhook ou fila.

Perguntas frequentes sobre a chave de acesso

Quantos dígitos tem a chave de acesso da NF-e?

A chave de acesso tem 44 posições: duas para a UF, quatro para ano e mês, 14 para o CNPJ ou CPF do emitente, duas para o modelo, três para a série, nove para o número, uma para a forma de emissão, oito para o código numérico e uma para o dígito verificador.

Como calcular o dígito verificador da NF-e?

Use módulo 11 sobre os 43 primeiros caracteres, com pesos de 2 a 9 aplicados da direita para a esquerda e reiniciados após o 9. Divida a soma por 11. Se o resto for 0 ou 1, o DV é 0; senão, o DV é 11 menos o resto.

Uma chave de acesso com DV correto garante que a nota existe?

Não. O dígito verificador só confirma que a sequência é consistente. Para saber se a nota foi autorizada, cancelada ou denegada, é preciso consultar a SEFAZ ou uma API que consulte por você.

O CNPJ alfanumérico muda a chave de acesso?

Muda o conteúdo, não o tamanho. As 12 primeiras posições do CNPJ dentro da chave passam a aceitar letras maiúsculas. O DV passa a ser calculado com o valor ASCII de cada caractere menos 48, conforme a Nota Técnica Conjunta 2025.001.

Dá para consultar NF-e pela chave de acesso sem captcha?

Pelo portal, não. O captcha existe para impedir automação. Sem captcha, as opções são o webservice da SEFAZ, que exige certificado digital, ou uma API de consulta que faça essa ponte.

Qual a diferença entre a chave da NF-e e a da NFC-e?

A estrutura da chave de acesso é a mesma. O que muda é o modelo nas posições 21 e 22: 55 para NF-e e 65 para NFC-e. Essa diferença decide para qual serviço a consulta deve ir.

Resumo para levar ao código

Normalize a entrada, valide a chave de acesso e o DV localmente, descarte duplicadas, consulte o cache e só então vá à rede. Com isso, a chave de acesso deixa de ser um campo de texto qualquer e vira um identificador confiável no seu sistema.

Antes de ir para produção, teste com dados reais. Abra sua conta grátis na API de Consulta NF-e do Hub do Desenvolvedor, use o validador deste artigo como primeira camada e veja a chave de acesso das suas notas voltar com os dados completos em JSON.


Compartilhe nas mídias: