Voter ID

The Brazilian voter registration number.

  • Parity matrix

Validate

Validates a voter ID: an 8-digit sequential number, a 2-digit UF code (01 to 28) and 2 modulus 11 check digits, at most 12 digits (Resolução TSE nº 23.659/2021, art. 36).

  • A 13-digit value is rejected. 2.4.0 accepted a 13-digit SP/MG form with a 9-digit sequential number.
  • The TSE drops the leading zeros of the sequential number when it issues the ID. A shorter value is left-padded with zeros to 12 digits before the check: 123450159 is checked as 000123450159. At least one sequential digit is required, so the shortest accepted value has 5 digits. 2.4.0 rejected these shorter values.
  • No official source gives the weights of the check digits or the SP/MG rule that turns a remainder of 0 into 1. They follow community references.
  • Mask characters: whitespace, ., - and /, alone or in a run, around and between the 0000 0000 00 00 groups (the same ones cpf.isValid reads). Any other character, a letter in particular, makes the value invalid. A separator inside a group is rejected, except between the digits of a sequential number written without its leading zeros, grouped from the right (123 4567 01 91).
  • Only a string is read. Any other type returns false.

Pending decision

The reference (JS) accepts whitespace, dots, hyphens and slashes around and between the groups, with a shortened sequential number grouped from the right (123 4567 01 91). Until 2.4.0 it accepted whitespace and dots only. Other libraries accept digits only. See the open decision in docs/findings.md.

ParameterTypeRequired
valuestringyes
returnsboolean

Check if a voter ID number is valid. A voter ID has at most 12 digits, so a 13-digit value is rejected.

  • A voter ID is an 8-digit sequential number, a 2-digit federative union code (01 to 28) and 2 check digits.
  • The TSE drops the leading zeros of the sequential number when it issues the ID, so a shorter value is read as the ID without them and left padded with zeros to 12 digits before it is checked (123450159 is checked as 000123450159). At least one sequential digit is required: the shortest accepted value has 5 digits.
  • Whitespace, dots, hyphens and slashes are accepted around and between the groups. Any other character makes the value invalid.
  • Resolução TSE nº 23.659/2021, art. 36, which revoked Resolução TSE nº 21.538/2003 (art. 140), fixes the layout, the federative union table and two check digits "determinados com base no 'Módulo 11'". It gives no weights and no rule per state: the weights, and the rule that turns a remainder of 0 into 1 for São Paulo (01) and Minas Gerais (02), have no official source and follow the community references below.
import { generateVoterId, isValidVoterId } from '@brazilian-utils/brazilian-utils';

const voterId = generateVoterId('SP');

isValidVoterId(voterId); // true
isValidVoterId('102385010671'); // true (12 digits)
isValidVoterId('123450159'); // true (000123450159 issued without its leading zeros)
isValidVoterId('1234567880191'); // false (13 digits, more than the 12 the TSE allows)
isValidVoterId('123456780124'); // false (invalid check digits)

Source: Resolução TSE nº 23.659/2021, art. 36 ("composto por até 12 algarismos", "os oito primeiros algarismos serão sequenciados, desprezando-se, na emissão, os zeros à esquerda"), brutils and siga0984.

Code: brazilian-utils/javascript
Try it with JavaScript isValidVoterId
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (52) and the result in each library voterId.isValid

Format

Formats a voter ID with the grouping 0000 0000 00 00.

  • A voter ID has at most 12 digits (Resolução TSE nº 23.659/2021, art. 36), so the function drops the digits after the 12th and has no 13-digit grouping. 2.4.0 grouped a 13-digit SP/MG value as 0000 0000 0 00 00.
  • The TSE drops the leading zeros of the sequential number when it issues the ID. By default a shorter value is formatted from the left, as a partial value. options.pad first left-pads it with zeros to 12 digits: 123450159 gives 0001 2345 01 59.
  • options.obfuscate (default false) hides the first 3 digits and the 2 check digits with *: ***4 5678 01 **. The UF code stays visible.
  • No authority publishes a masking rule for the voter ID. The rule is an analogy with the one the Leis de Diretrizes Orçamentárias set for publishing a CPF ("ocultar os três primeiros dígitos e os dois dígitos verificadores", Lei nº 12.309/2010, art. 87, § 5º, repeated up to the LDO 2026, Lei nº 15.321/2025, art. 163), not a published norm.
  • The mask hides by position. A voter ID given as a number has lost its leading zeros, so pass pad together with obfuscate for it.
  • A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number gives an empty string (2.4.0 read the digits of any number).
  • A value with no digits (empty, or only letters and symbols) returns an empty string, even with pad.
  • options.obfuscate is applied after pad, and is read for truthiness like pad: a non-boolean such as 1 hides the digits too, and 0 does not. The two can be combined (123450159 gives ***1 2345 01 **).

Pending decision

The reference (JS) formats only the characters an incomplete value has and returns an empty string for empty or invalid input. Other libraries return null. See the open decision in docs/findings.md.

ParameterTypeRequired
valuestring | numberyes
optionsFormatVoterIdOptionsno
options.padbooleanno
options.obfuscatebooleanno
returnsstring

Format a voter ID number with the 12-digit grouping 0000 0000 00 00.

  • Options (FormatVoterIdOptions): pad left pads the value with zeros up to 12 digits, restoring the leading zeros of a voter ID issued without them; obfuscate hides the first 3 digits and the 2 check digits, leaving the federative union code visible. The mask hides by position, so pass pad with obfuscate for a voter ID given as a number, which has lost its leading zeros: without it the mask shifts onto the check digits. An empty value, or one without digits, gives '' even with pad.
  • Without pad, a shorter value is formatted from the left, as a partially typed ID.
  • Digits past the 12th are dropped.
  • No authority publishes a masking rule for the voter ID, so obfuscate applies the one the Leis de Diretrizes Orçamentárias set for publishing a CPF ("ocultar os três primeiros dígitos e os dois dígitos verificadores", Lei nº 14.194/2021, art. 149, first set by Lei nº 12.309/2010, art. 87, § 5º), a number with the same structure.
import { formatVoterId } from '@brazilian-utils/brazilian-utils';

formatVoterId('123456780175'); // '1234 5678 01 75'
formatVoterId('123456780175', { obfuscate: true }); // '***4 5678 01 **'
formatVoterId('123450159', { pad: true }); // '0001 2345 01 59'
formatVoterId('123450159'); // '1234 5015 9' (read as a partially typed ID)
Code: brazilian-utils/javascript
Try it with JavaScript formatVoterId
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (45) and the result in each library voterId.format

Parse

Removes voter ID formatting and keeps only digits, capped at 12 digits for every UF.

  • A voter ID has at most 12 digits (Resolução TSE nº 23.659/2021, art. 36). 2.4.0 kept 13 digits when the UF digits were SP or MG.
  • A shorter value is returned as it is, not padded. voterId.isValid accepts that form, and voterId.format with pad restores the zeros.
  • A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number gives an empty string (2.4.0 read the digits of any number).
ParameterTypeRequired
valuestring | numberyes
returnsstring

Remove voter ID formatting, keep only digits, and cap the result to 12 digits. A shorter value is kept as it is, without adding leading zeros.

import { parseVoterId } from '@brazilian-utils/brazilian-utils';

parseVoterId('1234 5678 01 75'); // '123456780175'
parseVoterId('12345 01 59'); // '123450159'
Code: brazilian-utils/javascript
Try it with JavaScript parseVoterId
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (13) and the result in each library voterId.parse

Generate

Generates a valid random voter ID: 12 digits, unformatted, with the leading zeros of the sequential number kept.

  • state (a state code, or ZZ for a voter ID issued abroad) sets the UF code. Letter case and surrounding whitespace are ignored (" sp " is SP); 2.4.0 read a lowercase code as unknown. An unknown value falls back to ZZ (UF 28).
  • The result always has 12 digits. The same ID without the leading zeros of its sequential number is valid too (voterId.isValid reads it).
  • A value that is not a string also falls back to ZZ; the function never throws for state.
ParameterTypeRequired
stateStateCode | "ZZ"no
returnsstring

Generate a valid random voter ID number. The optional state argument (StateCode, or "ZZ" for a voter ID issued abroad) sets the federative union code.

  • state ignores letter case and surrounding whitespace ('sp' is 'SP'). An unknown state, or a value that is not a string, falls back to "ZZ" (UF 28).
  • The result always has 12 digits, the leading zeros of the sequential number included; the same ID without them is valid too.
import { generateVoterId } from '@brazilian-utils/brazilian-utils';

generateVoterId(); // valid random voter ID (abroad, "ZZ")
generateVoterId('SP'); // valid random voter ID for Sao Paulo
generateVoterId('XX'); // falls back to "ZZ" instead of throwing

Source: Lei nº 14.194/2021, art. 149, the CPF masking rule obfuscate borrows, first set by Lei nº 12.309/2010, art. 87, § 5º and repeated by the later LDOs (Lei nº 15.321/2025, art. 163, the one for 2026, repeats it).

Code: brazilian-utils/javascript
Try it with JavaScript generateVoterId
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (1) and the result in each library voterId.generate

Decode

Reads the fields of a voter ID: the sequential number, the federative union of the registration and the check digits.

  • Returns null exactly when voterId.isValid returns false; the input rules are the same.
  • The result has sequentialNumber (8 digits), federativeUnion (the code 01 to 28), stateCode (the state code, or null for 28, the voters abroad) and checkDigits (2 digits). Codes are strings that keep their leading zeros.
  • A voter ID issued without the leading zeros of its sequential number is read as voterId.isValid reads it, left-padded with zeros to 12 digits: 123450159 gives the sequentialNumber 00012345.
  • stateCode is the federative union of the registration, not necessarily where the voter lives today.
  • Each call returns a new object.
ParameterTypeRequired
valuestringyes
returnsVoterIdInfo | null

Read the fields of a voter ID, as a VoterIdInfo, or null when isValidVoterId would return false.

  • Fields: sequentialNumber (8 digits), federativeUnion (the code '01' to '28'), stateCode (a StateCode, or null for '28', the voters abroad) and checkDigits (2 digits). Codes are strings that keep their leading zeros.
  • A voter ID issued without the leading zeros of its sequential number is read as isValidVoterId reads it, left padded with zeros to 12 digits: '123450159' gives the sequentialNumber '00012345'.
  • The stateCode is the federative union of the registration, not necessarily where the voter lives today.
import { getVoterIdInfo } from '@brazilian-utils/brazilian-utils';

getVoterIdInfo('1023 8501 06 71');
// {
//   sequentialNumber: '10238501',
//   federativeUnion: '06',
//   stateCode: 'PR',
//   checkDigits: '71',
// }

getVoterIdInfo('000000002801'); // { sequentialNumber: '00000000', federativeUnion: '28', stateCode: null, checkDigits: '01' }
getVoterIdInfo('123456780124'); // null (invalid check digits)

Source: Resolução TSE nº 23.659/2021, art. 36.

Code: brazilian-utils/javascript
Try it with JavaScript getVoterIdInfo
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

Shared test cases (26) and the result in each library voterId.getInfo

Official sources

Last updated on

On this page