Skip to main content

Validate Brazilian CNPJ, CEI, CPF, PIS/PASEP, CEP, and municipal numbers

Project description

Validate Brazilian Identification Numbers

Python functions for working with CNPJ, CEI, CPF, PIS/PASEP, CEP, and município numbers, which identify firms, people, and places in Brazil.

Installation

pip install brazilnum

Usage Examples

Requires Python 3.9 or newer.

Validation Functions

Validate a CNPJ number for a firm, in this case Telefônica Brasil:

>>> from brazilnum.cnpj import validate_cnpj
>>> validate_cnpj('02.558.157/0001-62')
True
>>> validate_cnpj('02.558.157/0001-55')
False

As of 07/2026, CNPJ can also be issued in a new alphanumeric format:

>>> validate_cnpj('XP.B30.AW3/0001-84')
True
>>> validate_cnpj('xp.b30.aw3/0001-84')
True

Note: because CNPJ can contain letters, stray letters in the input make an identifier invalid as of version 0.9.0:

>>> validate_cnpj('CNPJ: 02.558.157/0001-62')
False

Integer input that is too short due to missing zeros is auto-corrected:

>>> validate_cnpj(2558157000162)
True
>>> validate_cnpj(2558157000162, autopad=False)
False

Missing values (None or NaN) are treated as invalid identifiers, so validation works on a stream of identifiers where some are missing:

>>> validate_cnpj(None)
False
>>> validate_cnpj(float('nan'))
False

Any other input type (e.g. a float or a list) raises a TypeError, since that usually signals a problem in the data pipeline that is better surfaced early than hidden by a False return. The formatting, padding, and parsing functions raise TypeError for missing values too, because there is no sensible way to format or parse a missing identifier. This behavior is shared by all validation functions in the package as of version 0.10.0.

Validate a CEI number, used for businesses that do not require a CNPJ:

>>> from brazilnum.cei import validate_cei
>>> validate_cei('11.583.00249/85')
True
>>> validate_cei('11.583.00249/84')
False
>>> validate_cei(115830024985)
True

Validate CPF and PIS/PASEP numbers for individuals:

>>> from brazilnum.pis import validate_pis
>>> validate_pis('125.6124.131-0')
True
>>> validate_pis('111.6124.131-0')
False

>>> from brazilnum.cpf import validate_cpf
>>> validate_cpf('968.811.342-58')
True
>>> validate_cpf('327.861.067-97')
False

Validation functions work with integer and unformatted input:

>>> validate_pis(12561241310)
True
>>> validate_cpf(96881134258)
True
>>> validate_pis('12561241310')
True
>>> validate_cpf('32786106797')
False

Formatting and Padding

Use the format function when displaying identifiers:

>>> from brazilnum.cnpj import format_cnpj
>>> format_cnpj('02558157000162')
'02.558.157/0001-62'
>>> format_cnpj('XPB30AW3000184')
'XP.B30.AW3/0001-84'

>>> from brazilnum.cei import format_cei
>>> format_cei('115830024985')
'11.583.00249/85'

>>> from brazilnum.pis import format_pis
>>> format_pis('12561241310')
'125.6124.131-0'

>>> from brazilnum.cpf import format_cpf
>>> format_cpf('96881134258')
'968.811.342-58'

There is a helper function to remove formatting from identifiers; it always returns a string:

>>> from brazilnum.util import clean_id
>>> clean_id('02.558.157/0001-62')
'02558157000162'

>>> clean_id(115830024985)
'115830024985'

If your data source stores identifiers as integers and leading zeros are missing, you can pad and validate them in one step:

>>> from brazilnum.cnpj import pad_cnpj
>>> pad_cnpj(2558157000162, validate=True)
('02558157000162', True)

>>> pad_cnpj(2558157000155, validate=True)
('02558157000155', False)

>>> pad_cnpj('PB3AW3W000133')
'0PB3AW3W000133'

>>> from brazilnum.cei import pad_cei
>>> pad_cei(115830024985, validate=True)
('115830024985', True)

You can skip the validation step:

>>> pad_cnpj(2558157000155, validate=False)
'02558157000155'

Padding works the same way for PIS/PASEP and CPF numbers:

>>> from brazilnum.pis import pad_pis
>>> pad_pis(12561241310, validate=True)
('12561241310', True)

>>> pad_pis(11161241310, validate=True)
('11161241310', False)

>>> from brazilnum.cpf import pad_cpf
>>> pad_cpf(4193675866, validate=True)
('04193675866', True)

>>> pad_cpf(4193675867, validate=True)
('04193675867', False)

CNPJ Parsing

The first 8 digits of CNPJs identify a firm, and the following 4 digits identify a specific business establishment owned by that firm. Headquarters is often establishment 0001. The cnpj_from_firm_id function will create a full CNPJ from the first 8 digits and a given establishment number:

>>> from brazilnum.cnpj import cnpj_from_firm_id
>>> cnpj_from_firm_id('02.558.157')
'02558157000162'

>>> cnpj_from_firm_id('02.558.157', establishment='0002')
'02558157000243'

>>> cnpj_from_firm_id('02.558.157', establishment='0002', formatted=True)
'02.558.157/0002-43'

This also works with the alphanumeric CNPJ format:

>>> cnpj_from_firm_id('XPB30AW3')
'XPB30AW3000184'

CNPJ can be parsed into firm, establishment, and check digit components:

>>> from brazilnum.cnpj import parse_cnpj
>>> parse_cnpj('02.558.157/0001-62')
CNPJ(cnpj='02.558.157/0001-62', firm='02.558.157', establishment='0001', check='62', valid=True)

>>> parse_cnpj('02.558.157/0001-62', formatted=False)
CNPJ(cnpj=2558157000162, firm=2558157, establishment=1, check=(6, 2), valid=True)

Alphanumeric CNPJs are parsed the same way. Since letters can't be represented as Python ints, formatted=False returns strings for the identifier components; the check digits are always numeric, so they are returned as integers in both cases:

>>> parse_cnpj('XPB30AW3000184')
CNPJ(cnpj='XP.B30.AW3/0001-84', firm='XP.B30.AW3', establishment='0001', check='84', valid=True)

>>> parse_cnpj('XPB30AW3000184', formatted=False)
CNPJ(cnpj='XPB30AW3000184', firm='XPB30AW3', establishment='0001', check=(8, 4), valid=True)

Note: as alphanumeric CNPJs become more common, a future release may switch parse_cnpj(..., formatted=False) to returning strings for all CNPJs, so avoid relying on the integer representation in new code.

CEP Parsing

Códigos de Endereçamentos Postais (zip codes) can be formatted and parsed:

>>> from brazilnum.cep import format_cep, parse_cep
>>> format_cep(13165000)
'13165-000'

>>> format_cep(1002010)
'01002-010'

>>> format_cep(73080)
'73080-000'

>>> parse_cep('01255-080', numeric=True)
CEP(cep=1255080, region=0, subregion=1, sector=12, subsector=125, division=1255, suffix=80)

>>> parse_cep('01255-080', numeric=False)
CEP(cep='01255-080', region='0', subregion='01', sector='012', subsector='0125', division='01255', suffix='080')

Correios has more information about the structure of CEP.

Municípios (Municipalities)

Validation of IBGE município (municipal) identifiers is also possible:

>>> from brazilnum.muni import validate_muni
>>> validate_muni(3550308)  # São Paulo
True

>>> validate_muni(4305871)  # Coronel Barros (see note below)
True

Note that 9 true codes do not follow the correct verification pattern. ENCAT has a technical note about this issue. The program correctly handles special codes like Coronel Barros, RS (see above).

If you need a list of municípios with names and coordinates, see poliquin/br-localidades. If you need historical and current codes with names, see paulofreitas/dtb-ibge.

Random Identifiers

If you need random CNPJ for database testing, use the random_cnpj function, which can return either unformatted or formatted identifiers:

from brazilnum.cnpj import random_cnpj
random_cnpj()                   # for a random, formatted CNPJ
random_cnpj(False)              # for a random, unformatted CNPJ
random_cnpj(alphanumeric=True)  # for a random alphanumeric CNPJ

Use random_cei for random CEI identifiers:

from brazilnum.cei import random_cei
random_cei()

The same thing exists for PIS/PASEP and CPF identifiers:

from brazilnum.pis import random_pis
random_pis()

from brazilnum.cpf import random_cpf
random_cpf()

Check Digits

If you're interested in the check digits, there are functions for calculating them that return integers:

>>> from brazilnum.cnpj import cnpj_check_digits
>>> cnpj_check_digits('02.558.157/0001-62')
(6, 2)

>>> from brazilnum.cei import cei_check_digit
>>> cei_check_digit('11.583.00249/85')
5

>>> from brazilnum.cpf import cpf_check_digits
>>> cpf_check_digits('041.936.758-66')
(6, 6)

>>> from brazilnum.pis import pis_check_digit
>>> pis_check_digit('125.6124.131-0')
0

CNPJ check digits are calculated from the first 12 digits:

>>> cnpj_check_digits('025581570001')
(6, 2)
>>> cnpj_check_digits('XPB30AW30001')
(8, 4)

The CEI check digit is calculated from the first 11 digits:

>>> cei_check_digit('11583002498')
5

CPF check digits are calculated from the first 9 digits:

>>> cpf_check_digits('041936758')
(6, 6)

The PIS/PASEP check digit is calculated from the first 10 digits:

>>> pis_check_digit('1256124131')
0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

brazilnum-0.10.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

brazilnum-0.10.0-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file brazilnum-0.10.0.tar.gz.

File metadata

  • Download URL: brazilnum-0.10.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for brazilnum-0.10.0.tar.gz
Algorithm Hash digest
SHA256 aca9d5364903eb74216790562f9e402761a86a5cdb232defbcc345f1e06d08ab
MD5 c31631712f54a9be92000378d5da5697
BLAKE2b-256 1106ac33f6320d0f5bb88a7f2542bf6058ec78f1553cd3f5ebc8eb7678116dba

See more details on using hashes here.

File details

Details for the file brazilnum-0.10.0-py3-none-any.whl.

File metadata

  • Download URL: brazilnum-0.10.0-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for brazilnum-0.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3739378978b814fa95867a288296fc885b0c11ce60a1dc8686aaf7a605cb8e33
MD5 89d6efa0d1971b229fae71c997d4f55a
BLAKE2b-256 545237092c355f7572e6c3d7e8e31701e055dc9547aa378571a0d66212a4a4e3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page