O número do título de eleitor quase sempre aparece em três blocos de quatro dígitos — 1234 5678 2097 — e esse agrupamento não corresponde aos campos internos do número. Os campos têm oito, dois e dois dígitos. O último bloco impresso mistura o código da unidade federativa com os dois dígitos verificadores, o que é suficiente para quebrar qualquer parser escrito olhando apenas para a máscara.
Anatomia dos doze dígitos
São doze algarismos decimais, sem letras e sem separador obrigatório. A divisão é fixa:
- Posições 1 a 8 — sequencial de inscrição atribuído pela Justiça Eleitoral no alistamento. Não há data, faixa etária nem código de município embutidos: é um contador, e nada nele é decodificável.
- Posições 9 e 10 — código da unidade federativa vinculada à inscrição, de
01a28. - Posições 11 e 12 — dígitos verificadores calculados por módulo 11, cada um com uma regra diferente.
O sequencial pode começar com zero, e o código de UF de São Paulo é literalmente 01. Guardar o título como inteiro perde esses zeros e transforma um número válido em um número de onze dígitos que nenhum validador aceita. A coluna correta é textual e de tamanho fixo: char(12) ou varchar(12), com a máscara aplicada só na exibição. A normalização é a de sempre — remover pontos, hífens e espaços, conferir que sobraram doze dígitos e validar sobre a forma limpa. Um padrão pronto para isso está no guia de regex para documentos brasileiros.
A tabela completa dos códigos por unidade federativa
São 28 códigos: os 27 entes federativos mais o código 28, usado por inscrições do exterior e normalmente exibido como ZZ. A ordem não é alfabética nem a numeração do IBGE — é uma sequência própria da Justiça Eleitoral, que começa por São Paulo e Minas Gerais. Qualquer par fora da faixa 01–28, incluindo 00, invalida o número antes mesmo do cálculo do dígito.
| Código | Unidade federativa | Exemplo |
|---|---|---|
| 01 | São Paulo (SP) | 1234 5678 0191 |
| 02 | Minas Gerais (MG) | 1234 5678 0299 |
| 03 | Rio de Janeiro (RJ) | 1234 5678 0396 |
| 04 | Rio Grande do Sul (RS) | 1234 5678 0493 |
| 05 | Bahia (BA) | 1234 5678 0590 |
| 06 | Paraná (PR) | 1234 5678 0698 |
| 07 | Ceará (CE) | 1234 5678 0795 |
| 08 | Pernambuco (PE) | 1234 5678 0892 |
| 09 | Santa Catarina (SC) | 1234 5678 0990 |
| 10 | Goiás (GO) | 1234 5678 1090 |
| 11 | Maranhão (MA) | 1234 5678 1198 |
| 12 | Paraíba (PB) | 1234 5678 1295 |
| 13 | Pará (PA) | 1234 5678 1392 |
| 14 | Espírito Santo (ES) | 1234 5678 1490 |
| 15 | Piauí (PI) | 1234 5678 1597 |
| 16 | Rio Grande do Norte (RN) | 1234 5678 1694 |
| 17 | Alagoas (AL) | 1234 5678 1791 |
| 18 | Mato Grosso (MT) | 1234 5678 1899 |
| 19 | Mato Grosso do Sul (MS) | 1234 5678 1996 |
| 20 | Distrito Federal (DF) | 1234 5678 2097 |
| 21 | Sergipe (SE) | 1234 5678 2194 |
| 22 | Amazonas (AM) | 1234 5678 2291 |
| 23 | Rondônia (RO) | 1234 5678 2399 |
| 24 | Acre (AC) | 1234 5678 2496 |
| 25 | Amapá (AP) | 1234 5678 2593 |
| 26 | Roraima (RR) | 1234 5678 2690 |
| 27 | Tocantins (TO) | 1234 5678 2798 |
| 28 | Exterior (ZZ) | 1234 5678 2895 |
Repare na coluna de exemplos: o primeiro dígito verificador é 9 nos 28 casos. Isso não é coincidência nem erro da tabela — é consequência direta do algoritmo, que calcula o primeiro dígito apenas sobre o sequencial. Trocar a UF muda somente o segundo.
Zona e seção não estão no número
A confusão nasce do documento físico, onde o número da inscrição, a zona e a seção são impressos lado a lado, no mesmo bloco visual. Muita gente conclui que o terceiro grupo de quatro dígitos é a zona. Não é: nos doze dígitos não existe campo de zona nem de seção, e nenhuma operação aritmética sobre eles recupera essa informação.
Zona e seção descrevem onde a pessoa vota. A zona é a circunscrição da Justiça Eleitoral que administra o eleitorado de uma área, com seu cartório; a seção é o agrupamento menor, associado a um local e a uma mesa de votação. São atributos da situação eleitoral corrente, consultáveis nos serviços do TSE, e mudam com transferências e com a reorganização dos locais de votação — sem que isso esteja refletido nos doze dígitos.
Na modelagem, isso significa três campos independentes: titulo, zona e secao. Derivar os dois últimos do primeiro é impossível, e formulários que pedem zona e seção junto com o número estão pedindo dados que só vêm da consulta oficial ou do próprio eleitor.
O cálculo dos dois dígitos verificadores, resolvido
O título usa módulo 11 em dois estágios, e o segundo estágio é incomum: ele não percorre o número inteiro. O primeiro dígito sai dos oito algarismos do sequencial, com pesos crescentes de 2 a 9. Tomando o sequencial 12345678 e o Distrito Federal (20):
| Caractere | Peso | Produto |
|---|---|---|
| 1 | 2 | 2 |
| 2 | 3 | 6 |
| 3 | 4 | 12 |
| 4 | 5 | 20 |
| 5 | 6 | 30 |
| 6 | 7 | 42 |
| 7 | 8 | 56 |
| 8 | 9 | 72 |
| Soma | 240 | |
240 ÷ 11 → resto 9
O resto é o próprio dígito (só o resto 10 recebe tratamento especial).
Dígito verificador = 9
O segundo dígito opera sobre apenas três valores: os dois algarismos do código da UF e o primeiro dígito recém-calculado, com pesos 7, 8 e 9. O sequencial não entra nessa conta.
| Caractere | Peso | Produto |
|---|---|---|
| 2 | 7 | 14 |
| 0 | 8 | 0 |
| 9 | 9 | 81 |
| Soma | 95 | |
95 ÷ 11 → resto 7
O resto é o próprio dígito.
Dígito verificador = 7
Juntando tudo: 12345678 + 20 + 97 = 1234 5678 2097. Quando o resto de qualquer um dos dois estágios é 10, o dígito vira 0. É o caso de 1000 0007 0302, do Rio de Janeiro: a soma do sequencial dá 65, o resto é 10 e o primeiro dígito vira 0; o segundo estágio soma 0×7 + 3×8 + 0×9 = 24, resto 2.
A consequência prática dessa estrutura é que o segundo dígito é função exclusiva do par (código da UF, primeiro dígito). São no máximo 280 combinações de entrada, o que permite substituir o segundo estágio por uma tabela pré-calculada quando a validação é feita em volume — e explica por que o dígito verificador do título detecta bem erros de digitação, mas serve de muito pouco como evidência de que o número existe. A ideia geral do algoritmo está no guia de módulo 11.
A exceção de São Paulo e Minas Gerais
Nos títulos emitidos em São Paulo (01) e Minas Gerais (02), o resto 0 não produz o dígito 0: produz o dígito 1. A regra vale para os dois estágios do cálculo, e é a única diferença de tratamento por estado em todo o algoritmo.
O sequencial 11111111 mostra o efeito. A soma ponderada dá 1×(2+3+4+5+6+7+8+9) = 44, e 44 é divisível por 11 — resto 0. Em qualquer outro estado o primeiro dígito seria 0. Em São Paulo ele é 1, e o segundo estágio passa a somar 0×7 + 1×8 + 1×9 = 17, resto 6: o título é 1111 1111 0116. O mesmo sequencial em Minas Gerais soma 0×7 + 2×8 + 1×9 = 25, resto 3, gerando 1111 1111 0213.
Fora desses dois códigos, o resto 0 continua valendo 0, e isso aparece na massa de teste mais abaixo: 6021 9483 2003, do Distrito Federal, tem resto 0 no primeiro estágio e primeiro dígito 0. 4801 2377 0620, do Paraná, tem resto 0 no segundo estágio e segundo dígito 0. Nenhum dos dois seria escrito assim se a UF fosse 01 ou 02.
Por que dois validadores discordam do mesmo título
Boa parte das implementações que circulam por aí ignora a exceção de SP/MG. Para essas, o sequencial 11111111 em São Paulo produz 1111 1111 0108, e não 1111 1111 0116. Os dois números não podem estar certos ao mesmo tempo: cada validador aceita o seu e rejeita o do outro. Quando um cadastro reclama que um título "válido no outro sistema" foi recusado, é aqui que se deve olhar primeiro.
A divergência só acontece quando algum dos dois restos dá 0 em um título de SP ou MG. É um subconjunto pequeno e perfeitamente identificável, então dá para calcular os dígitos nas duas interpretações e comparar:
const SP_MG = new Set(["01", "02"]);
function applyRest(rest: number, ufCode: string, withException: boolean): number {
if (rest === 10) return 0;
if (withException && rest === 0 && SP_MG.has(ufCode)) return 1;
return rest;
}
function checkDigits(seq8: string, ufCode: string, withException: boolean): string {
let sum1 = 0;
for (let i = 0; i < 8; i++) {
sum1 += Number(seq8[i]) * (i + 2);
}
const dv1 = applyRest(sum1 % 11, ufCode, withException);
const sum2 = Number(ufCode[0]) * 7 + Number(ufCode[1]) * 8 + dv1 * 9;
const dv2 = applyRest(sum2 % 11, ufCode, withException);
return String(dv1) + String(dv2);
}
/** Sequenciais de SP/MG em que as duas interpretações divergem. */
function isContestedBase(seq8: string, ufCode: string): boolean {
if (!SP_MG.has(ufCode)) return false;
return checkDigits(seq8, ufCode, true) !== checkDigits(seq8, ufCode, false);
}O gerador de título descarta os sequenciais em que isContestedBase retorna verdadeiro. Números gerados por ele passam nas duas leituras da regra, o que evita que uma massa de teste falhe por causa de uma decisão de implementação de terceiros em vez de um defeito real. Para testar a exceção de propósito, o caminho é o contrário: use justamente um sequencial ambíguo e fixe qual interpretação o seu sistema adota.
O que o número não prova
Dígitos verificadores corretos dizem que a sequência é bem formada, e só. Não dizem que a inscrição existe, que está regular, que não há pendências, nem se a pessoa é obrigada a votar. Essa informação vem dos serviços do TSE, não da aritmética — a mesma distinção entre forma e existência que vale para o CPF e está detalhada em válido não é o mesmo que existente.
O código de UF também é frequentemente superinterpretado. Ele identifica a unidade federativa vinculada à inscrição, não o estado de nascimento, não o endereço atual e não o local onde a pessoa vota hoje. Usar esse par de dígitos como filtro de domicílio em regra de negócio produz falsos negativos silenciosos, do mesmo tipo que a leitura da região fiscal do CPF costuma provocar.
Números reais de título são dado pessoal e vinculam identidade civil a exercício político, o que os coloca entre os campos que menos convém arrastar para bancos de homologação. A alternativa, aqui e nos demais documentos, é massa fictícia com dígito válido — o guia sobre LGPD e dados de teste trata do porquê.
Massa de teste por estado
Os títulos abaixo têm sequenciais variados, cobrem os casos-limite do algoritmo e foram conferidos contra a implementação do site. Nenhum deles é ambíguo, então servem tanto para validadores que aplicam a exceção de SP/MG quanto para os que não aplicam.
| UF | Título | O que exercita |
|---|---|---|
| SP (01) | 2468 0135 0124 | resto 2 no 1º DV, resto 4 no 2º |
| MG (02) | 9182 7364 0213 | resto 1 no 1º DV — a exceção não se aplica |
| RJ (03) | 5550 0012 0353 | sequencial com zeros no meio |
| RJ (03) | 1000 0007 0302 | resto 10 no 1º DV, que vira 0 |
| RS (04) | 3321 0987 0493 | mesmo par de DV do exemplo 1234 5678 0493 |
| BA (05) | 7065 4321 0515 | — |
| PR (06) | 4801 2377 0620 | resto 0 no 2º DV, que permanece 0 fora de SP/MG |
| SC (09) | 8237 0145 0906 | resto 10 no 1º DV |
| DF (20) | 6021 9483 2003 | resto 0 no 1º DV, que permanece 0 fora de SP/MG |
| AM (22) | 1739 5028 2208 | sequencial idêntico ao anterior em soma |
Para gerar os seus em vez de copiar os de cima, vale fixar o sequencial e variar a UF — a massa fica determinística e o teste não depende de aleatoriedade:
const UF_CODES = ["01", "03", "06", "20", "26"];
const SEQ = "12345678";
export const TITULOS_FIXTURE = UF_CODES.map(
(uf) => SEQ + uf + checkDigits(SEQ, uf, true),
);
// ["123456780191", "123456780396", "123456780698", ...]Quando o volume é maior, ou quando você precisa de títulos de uma UF específica já formatados em blocos de quatro, o gerador de título de eleitor faz isso em lote e valida números existentes na mesma tela, mostrando a UF detectada nos dígitos 9 e 10.