What kind of request is this?
New utilities (validate/format/parse/lookup), three related families of fiscal codes that the library does not cover yet. Each one follows the conventions already in place (isValidX, formatX, parseX, getX returning { code, description } | null, zero runtime dependencies, datasets generated by a script under scripts/ and refreshed by the Update datasets workflow).
Nothing below is implemented; this issue is the place to agree on scope and API first. Every layout, length or check-digit statement that could not be verified against the official source while writing this is marked to confirm: please do not implement any of those from memory.
1. IBS/CBS (tax reform): CST IBS/CBS and cClassTrib tables
Motivation
The tax reform (Emenda Constitucional 132/2023, Lei Complementar 214/2025) introduces IBS and CBS, and the electronic fiscal documents (NF-e, NFC-e, NFS-e nacional, CT-e...) carry two new code sets for them: the CST IBS/CBS (Código de Situação Tributária) and the cClassTrib (código de classificação tributária). Any system emitting or reading fiscal documents from 2026 on has to validate these codes and show their descriptions, exactly what isValidCfop/getCfop and isValidCst/isValidCsosn do for the older code sets today.
Proposed API
Modelled on getCfop/isValidCfop (lookup table + validator) and on isValidCst (options.tax selecting the table):
type CstIbsCbs = { code: string; description: string };
isValidCstIbsCbs(value: string | number): boolean;
getCstIbsCbs(value: string | number): CstIbsCbs | null;
type ClassTrib = { code: string; description: string; cst: string /* the CST IBS/CBS the classification belongs to */ };
isValidClassTrib(value: string | number): boolean;
getClassTrib(value: string | number): ClassTrib | null;
Open question on naming: isValidCstIbsCbs vs. extending isValidCst with tax: "ibs" | "cbs" (the tables are shared between IBS and CBS, so a single "ibscbs" value, or a separate function, may read better). getClassTrib could also take the CST as an option to narrow the lookup.
Primary source to cite
- Nota Técnica RTC (reforma tributária do consumo) published on the Portal da NF-e (https://www.nfe.fazenda.gov.br) and the "Tabelas de CST e cClassTrib" published with it by the Comitê Gestor do IBS / Receita Federal (gov.br). The exact document names, versions and download URLs are to confirm.
- Lei Complementar 214/2025 for the legal definitions.
Open points
- Code lengths and formats of the CST IBS/CBS (3 digits, to confirm) and of the cClassTrib (6 digits, to confirm); whether a cClassTrib is only valid together with a specific CST (the published table pairs them, to confirm).
- The tables are still being amended by new versions of the Nota Técnica; the dataset script has to pin the version it reads and the
Update datasets workflow has to pick new versions up.
- Whether descriptions (long legal texts) should ship in the bundle or only the codes, given the bundle-size table in
docs/getting-started.md.
2. NFS-e nacional: access key, NBS codes and the LC 116/2003 service list
Motivation
The national NFS-e standard (Sistema Nacional NFS-e, gov.br/nfse) gives service invoices an access key like the NF-e one, and its layout requires the service to be identified by a NBS code (Nomenclatura Brasileira de Serviços) and by an item of the service list of Lei Complementar 116/2003. The library already has isValidNfeKey/formatNfeKey/parseNfeKey/getNfeKeyInfo for the NF-e family; the NFS-e key is the natural next step, and the two code lists are lookups in the style of getCnae/getCbo.
Proposed API
isValidNfseKey(value: string): boolean;
formatNfseKey(value: string, options?: FormatNfseKeyOptions): string;
parseNfseKey(value: string | number): string;
getNfseKeyInfo(value: string): NfseKeyInfo | null; // the fields the key encodes, mirroring getNfeKeyInfo
type Nbs = { code: string; description: string };
isValidNbs(value: string | number): boolean;
getNbs(value: string | number): Nbs | null;
formatNbs(value: string | number): string;
type ServiceItem = { code: string; description: string }; // LC 116/2003 list, e.g. "1.01"
isValidServiceItem(value: string | number): boolean;
getServiceItem(value: string | number): ServiceItem | null;
Primary source to cite
- Modelo da NFS-e de padrão nacional, "Leiaute" / "Manual de orientação" in the technical documentation of https://www.gov.br/nfse (document names and versions to confirm).
- NBS: the Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que Produzam Variações no Patrimônio published by MDIC/Receita Federal (edition and URL to confirm).
- Lei Complementar 116/2003, "Lista de serviços anexa" (https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm).
Open points
- The access key layout: total length, the fields it concatenates (IBGE municipality code, environment, issuer registration type and number, NFS-e number, issue year/month, numeric code, check digit) and the check-digit rule (modulo 11, to confirm against the official layout before any of it is coded). Whether the key is numeric only or may carry the alphanumeric CNPJ (to confirm).
- The NBS code length and mask (to confirm), and whether the lookup should ship the full nomenclature (it is large; compare with the NCM table already in the package).
- The LC 116/2003 list: the exact item numbering (
1.01 style, to confirm), how sub-items and municipal variations are handled, and the source to generate it from (the law text has no machine-readable form, so the script may have to parse the HTML of the law or a gov.br dataset, to confirm).
3. CEST (Convênio ICMS 142/2018)
Motivation
The CEST (Código Especificador da Substituição Tributária) identifies goods subject to ICMS-ST and is mandatory in NF-e/NFC-e items for those goods. It sits next to NCM and CFOP, both already covered, and is a frequent source of rejections when malformed or not in the current annexes.
Proposed API
Modelled on formatNcm/parseNcm/isValidNcm and getCfop:
type Cest = { code: string; description: string; segment: string /* annex/segment name */ };
isValidCest(value: string | number): boolean;
formatCest(value: string | number, options?: FormatCestOptions): string; // pad like formatNcm
parseCest(value: string | number): string;
getCest(value: string | number): Cest | null;
Primary source to cite
Open points
- The CEST format: 7 digits in three groups, segment / item / specification, printed as
NN.NNN.NN (to confirm against the convênio text).
- Whether the lookup should also carry the NCM codes each CEST is tied to in the annexes (the annex rows pair CEST, NCM/SH and description), which would enable an
isValidCest(value, { ncm }) cross-check later.
- The generator script: the annexes are published as HTML/PDF and are amended by later convênios, so the parsing approach and the version pinning are open, as for CFOP (
scripts/cfop.ts).
Checklist
What kind of request is this?
New utilities (validate/format/parse/lookup), three related families of fiscal codes that the library does not cover yet. Each one follows the conventions already in place (
isValidX,formatX,parseX,getXreturning{ code, description } | null, zero runtime dependencies, datasets generated by a script underscripts/and refreshed by theUpdate datasetsworkflow).Nothing below is implemented; this issue is the place to agree on scope and API first. Every layout, length or check-digit statement that could not be verified against the official source while writing this is marked to confirm: please do not implement any of those from memory.
1. IBS/CBS (tax reform): CST IBS/CBS and cClassTrib tables
Motivation
The tax reform (Emenda Constitucional 132/2023, Lei Complementar 214/2025) introduces IBS and CBS, and the electronic fiscal documents (NF-e, NFC-e, NFS-e nacional, CT-e...) carry two new code sets for them: the CST IBS/CBS (Código de Situação Tributária) and the cClassTrib (código de classificação tributária). Any system emitting or reading fiscal documents from 2026 on has to validate these codes and show their descriptions, exactly what
isValidCfop/getCfopandisValidCst/isValidCsosndo for the older code sets today.Proposed API
Modelled on
getCfop/isValidCfop(lookup table + validator) and onisValidCst(options.taxselecting the table):Open question on naming:
isValidCstIbsCbsvs. extendingisValidCstwithtax: "ibs" | "cbs"(the tables are shared between IBS and CBS, so a single"ibscbs"value, or a separate function, may read better).getClassTribcould also take the CST as an option to narrow the lookup.Primary source to cite
Open points
Update datasetsworkflow has to pick new versions up.docs/getting-started.md.2. NFS-e nacional: access key, NBS codes and the LC 116/2003 service list
Motivation
The national NFS-e standard (Sistema Nacional NFS-e, gov.br/nfse) gives service invoices an access key like the NF-e one, and its layout requires the service to be identified by a NBS code (Nomenclatura Brasileira de Serviços) and by an item of the service list of Lei Complementar 116/2003. The library already has
isValidNfeKey/formatNfeKey/parseNfeKey/getNfeKeyInfofor the NF-e family; the NFS-e key is the natural next step, and the two code lists are lookups in the style ofgetCnae/getCbo.Proposed API
Primary source to cite
Open points
1.01style, to confirm), how sub-items and municipal variations are handled, and the source to generate it from (the law text has no machine-readable form, so the script may have to parse the HTML of the law or a gov.br dataset, to confirm).3. CEST (Convênio ICMS 142/2018)
Motivation
The CEST (Código Especificador da Substituição Tributária) identifies goods subject to ICMS-ST and is mandatory in NF-e/NFC-e items for those goods. It sits next to NCM and CFOP, both already covered, and is a frequent source of rejections when malformed or not in the current annexes.
Proposed API
Modelled on
formatNcm/parseNcm/isValidNcmandgetCfop:Primary source to cite
Open points
NN.NNN.NN(to confirm against the convênio text).isValidCest(value, { ncm })cross-check later.scripts/cfop.ts).Checklist