Estrutura da Chave de Acesso da NFS-e (49 dígitos + Dígito Verificador)
A geração da chave de acesso da NFS-e Nacional segue uma estrutura padronizada de 49 dígitos fixos, composta por informações como município, ambiente, tipo de inscrição, CPF/CNPJ, número da nota, ano, mês e código complementar. Sobre esses 49 dígitos aplica-se um dígito verificador (DV) calculado pelo módulo 11 adaptado, garantindo a integridade da chave.
Nesse exemplo essa chave é montada de forma determinística utilizando o sprintf no PHP, que assegura o preenchimento com zeros à esquerda e o comprimento correto de cada campo.
Além disso, o cálculo do DV segue a lógica de multiplicadores cíclicos de 2 a 9, aplicados sequencialmente a todos os dígitos, reforçando a validação e evitando inconsistências.
Estrutura da chave (49 dígitos) + Digito Verificador
Cód.Mun. (7) +
Amb.Ger. (1) +
Tipo Insc. Federal (1) +
CPF/CNPJ (14) +
Nº NFS-e (13) +
Ano (2) +
Mês (2) +
Código (9) +
DV (1)
Como o sprintf monta
$cMun = 3550308; // São Paulo
$ambGer = 2; // Nacional
$tIncr = 2; // Jurídica
$cnpj = 12345678000195;
$numero = 123;
$ano = 25; // 2025
$mes = 9;
$codigo = 456789; // Pode ser gerado randômico
$format = "%07d%01d%01d%014d%013d%02d%02d%09d";
$key = sprintf($format,
$cMun,
$ambGer,
$tIncr,
$cnpj,
$numero,
$ano,
$mes,
$codigo
);
Explicação do sprintf:
%07d → número com 7 dígitos, completado à esquerda com zeros (→ $cMun)
%01d → número com 1 dígito (→ $ambGer)
%01d → número com 1 dígito (→ $tIncr)
%014d → número com 14 dígitos, zero à esquerda (→ $cnpj ou CPF)
%013d → número com 13 dígitos (→ $numero da NFS-e)
%02d → número com 2 dígitos (→ $ano, ex: 25 para 2025)
%02d → número com 2 dígitos (→ $mes, ex: 09)
%09d → número com 9 dígitos (→ $codigo, 456789)
Diferenças em relação ao Módulo 11 “clássico”
-
Multiplicadores fixos [2–9] em sequência cíclica
-
No módulo 11 tradicional, a regra mais comum é multiplicar da direita para a esquerda usando pesos de 2 até 9, reiniciando em 2 depois do 9.
-
Aqui também se usa
[2,3,4,5,6,7,8,9], mas o loop está programado de uma forma específica: umforinterno de 8 passos que sempre recomeça a sequência, até consumir os 49 dígitos.
➝ Isso garante que todos os 49 caracteres sejam multiplicados em ciclos exatos de 2 a 9.
-
public function digitoVerificador(string $key): string
{
if (strlen($key) != 49) {
return '';
}
$multipliers = [2, 3, 4, 5, 6, 7, 8, 9];
$iCount = 48;
$weightedSum = 0;
while ($iCount >= 0) {
for ($mCount = 0; $mCount < 8 && $iCount >= 0; $mCount++) {
$sub = (int)$key[$iCount];
$weightedSum += $sub * $multipliers[$mCount];
$iCount--;
}
}
$vdigit = 11 - ($weightedSum % 11);
if ($vdigit > 9) {
$vdigit = 0;
}
return (string)$vdigit;
}