Fiscal glossary
The vocabulary this documentation uses. Each entry says what the term is, where it shows up in a stackin call, and links to where the docs go deeper.
Request fields
Every field you fill in, with the name it carries in each SDK and the tag it becomes in the XML. The names are English; what they mean is Brazilian fiscal law.
Document
| Field | SDK (Python / Go / PHP) | Type | Required on | XML tag | |
|---|---|---|---|---|---|
document_type | py·document_typego·DocumentTypephp/ts·documentType | "nfe" | "nfse" | nfenfse | mod | |
| Description Which document to issue. | |||||
client_name | py·client_namego·ClientNamephp/ts·clientName | string (1–120) | nfenfse | dest/xNome | |
| Description The legal name of whoever receives it. In homologation the SEFAZ requires the test phrase instead of the real name — stackin substitutes it for you. | |||||
tax_id | py·tax_idgo·TaxIDphp/ts·taxId | string (11 | 14) | nfenfse | dest/CPF · dest/CNPJ | |
| Description The recipient's tax document: a CPF at 11 digits, a CNPJ at 14. You never say which — the length decides. Applies to both NF-e and NFS-e. Since 2026-07-31 a CNPJ may carry letters in its first 12 characters. | |||||
items[] | py·itemsgo·Itemsphp/ts·items | Product[] | nfenfse | det | |
| Description The invoice's lines. Each is a product (NF-e) or a service (NFS-e). | |||||
recipient_address | py·recipient_addressgo·RecipientAddressphp/ts·recipientAddress | Address | nfe | dest/enderDest | |
| Description The recipient's address. Required and complete on NF-e; optional on NFS-e. | |||||
series | py·seriesgo·Seriesphp/ts·series | string | — | ide/serie | |
| Description The document's series. Omitted, stackin uses the series configured on the company. | |||||
number | py·numbergo·Numberphp/ts·number | string | — | ide/nNF | |
| Description The document's number. Omitted, stackin takes the next in sequence — which is the right behaviour in most cases. | |||||
contingency | py·—go·—php/ts·— | boolean | nfe | ide/tpEmis | |
| Description Issues in contingency when the state's SEFAZ is down. It changes the issuance type in the XML and where the document is transmitted. API only — no SDK exposes this field yet. | |||||
Idempotency-Key | py·idempotency_keygo·IdempotencyKeyphp/ts·idempotencyKey | string | — | — | |
| Description The safe-retry key. The same key with the same body replays the stored answer instead of issuing again — it is what stops a timeout becoming a duplicate invoice. | |||||
Item
| Field | SDK (Python / Go / PHP) | Type | Required on | XML tag | |
|---|---|---|---|---|---|
items[].description | py·descriptiongo·Descriptionphp/ts·description | string (1–120) | nfenfse | prod/xProd | |
| Description The product or service description, as it appears on the invoice and the DANFE. | |||||
items[].unit_price | py·unit_pricego·UnitPricephp/ts·unitPrice | decimal (10) | nfenfse | prod/vUnCom | |
| Description The price of one unit. Takes up to 10 decimal places. | |||||
items[].amount | py·amountgo·Amountphp/ts·amount | decimal (2) | nfenfse | prod/vProd | |
| Description The line's gross total, before discount, freight, insurance and other expenses. Two decimal places. | |||||
items[].product.quantity | py·quantitygo·Quantityphp/ts·quantity | decimal (4) | nfe | prod/qCom | |
| Description The line's quantity. Up to 4 decimal places — a fractional quantity is normal for bulk goods. | |||||
items[].product.unit | py·unitgo·Unitphp/ts·unit | string (≤6) | nfe | prod/uCom | |
| Description The commercial unit: UN, CX, KG, L. Free text, up to 6 characters. | |||||
items[].product.barcode | py·barcodego·Barcodephp/ts·barcode | string | — | prod/cEAN | |
| Description The product's real GTIN. Omitted, the XML carries | |||||
items[].product.discount | py·discountgo·Discountphp/ts·discount | decimal (2) | — | prod/vDesc | |
| Description Product discount, for NF-e. It reduces the line's gross amount and cannot exceed it. The NFS-e service discount is a different field: | |||||
items[].product.freight | py·freightgo·Freightphp/ts·freight | decimal (2) | — | prod/vFrete | |
| Description Freight apportioned to this line. | |||||
items[].product.insurance | py·insurancego·Insurancephp/ts·insurance | decimal (2) | — | prod/vSeg | |
| Description Insurance apportioned to this line. | |||||
items[].product.other_expenses | py·other_expensesgo·OtherExpensesphp/ts·otherExpenses | decimal (2) | — | prod/vOutro | |
| Description Other incidental expenses on the line. | |||||
items[].discount | py·discountgo·Discountphp/ts·discount | decimal (2) | nfse | vDescCondIncond/vDescIncond | |
| Description Unconditional discount on a service, for NFS-e. It comes off the taxable amount — not to be confused with the product discount, | |||||
items[].service_code | py·service_codego·ServiceCodephp/ts·serviceCode | string | nfse | cServ/cTribNac | |
| Description The item from the LC 116 list — | |||||
items[].tax_retained | py·tax_retainedgo·TaxRetainedphp/ts·taxRetained | boolean | nfse | tribMun/tpRetISSQN | |
| Description ISSQN withheld by the buyer. NFS-e only. | |||||
items[].observations | py·observationsgo·Observationsphp/ts·observations | string (≤2000) | nfse | infAdic/infCpl | |
| Description Notes printed on the invoice body. NFS-e only. | |||||
Item — Brazil-specific
| Field | SDK (Python / Go / PHP) | Type | Required on | XML tag | |
|---|---|---|---|---|---|
items[].product.br.ncm | py·ncmgo·NCMphp/ts·ncm | string (8) | nfe | prod/NCM | |
| Description Mercosur goods classification, 8 digits. Required on every NF-e item. | |||||
items[].product.br.cfop | py·cfopgo·CFOPphp/ts·cfop | string (4) | nfe | prod/CFOP | |
| Description Nature of the operation, 4 digits. Required on every NF-e item. | |||||
items[].product.br.cest | py·cestgo·CESTphp/ts·cest | string (7) | — | prod/CEST | |
| Description Tax-substitution code, 7 digits. Only when the goods are under that regime. | |||||
items[].product.br.tax | py·taxgo·Taxphp/ts·tax | Tax | nfe | imposto | |
| Description The item's tax groups — ICMS, IPI, PIS, COFINS. A fiscal decision by the issuer; stackin never infers it. | |||||
items[].product.br.manufacturer_cnpj | py·manufacturer_cnpjgo·ManufacturerCNPJphp/ts·manufacturerCnpj | string (14) | — | prod/CNPJFab | |
| Description The manufacturer's CNPJ, when the operation requires naming it. | |||||
items[].product.br.ibs_cbs | py·ibs_cbsgo·IbsCbsphp/ts·ibsCbs | IbsCbs | nfe | imposto/IBSCBS | |
| Description The IBS/CBS group from the tax reform. Rates and CST come from you; the amounts are derived from them. | |||||
Recipient address
| Field | SDK (Python / Go / PHP) | Type | Required on | XML tag | |
|---|---|---|---|---|---|
recipient_address.street | py·streetgo·Streetphp/ts·street | string | nfe | enderDest/xLgr | |
| Description The recipient's street. | |||||
recipient_address.number | py·numbergo·Numberphp/ts·number | string | nfe | enderDest/nro | |
| Description The building number. With none, use | |||||
recipient_address.neighborhood | py·neighborhoodgo·Neighborhoodphp/ts·neighborhood | string | nfe | enderDest/xBairro | |
| Description The neighborhood. | |||||
recipient_address.city | py·citygo·Cityphp/ts·city | string | nfe | enderDest/xMun | |
| Description The municipality's name — but | |||||
recipient_address.state | py·statego·Statephp/ts·state | string (2) | nfe | enderDest/UF | |
| Description The two-letter state. | |||||
recipient_address.zip_code | py·zip_codego·ZipCodephp/ts·zipCode | string (8) | nfe | enderDest/CEP | |
| Description The postal code, 8 digits, no hyphen. | |||||
recipient_address.city_code | py·city_codego·CityCodephp/ts·cityCode | string (7) | nfe | enderDest/cMun | |
| Description The 7-digit IBGE municipality code. It is what the SEFAZ actually reads. | |||||
Documents
- NF-e
- Model 55, issued on every movement of goods. What sets it apart in practice: each item needs an NCM and a CFOP, the recipient needs a full address with the IBGE municipality code, and authorization is state-level — the issuer's own SEFAZ answers. It is the only one that accepts a correction letter and range invalidation.
document_type: "nfe"ReferencesPortal Nacional da NF-eEsquemas XML espelhadosSee in the API - NFS-e
- A municipal service document. There are no goods, so there is no NCM and no CFOP: each item needs a description, a price and the LC 116 service code. The recipient's address is optional. There is no correction letter — correcting means cancelling and issuing again, within the municipality's window.
document_type: "nfse"ReferencesNFS-e Nacional (gov.br)Lei Complementar 116/2003See in the API - DPS
- This is what actually goes up to the national environment: the DPS is the declaration the issuer sends, and the invoice is what the ADN returns from it. You never assemble a DPS on stackin — the API builds it from the business fields and stores the resulting XML.ReferencesNFS-e — documentação técnicaPublicações NFS-e espelhadas
- DANFE
- The paper that travels with the cargo, carrying the access key as a barcode for roadside inspection. It is not the fiscal document: it is a representation of one. A DANFE with no matching authorized XML proves nothing.
GET /invoices/{access_key}/pdfReferencesPortal Nacional da NF-eSee in the API - DANFSe
- The printed representation of an NFS-e, produced by the national environment. Same relationship: the legal value is in the XML, the PDF is for a human to read.
GET /invoices/{access_key}/pdfReferencesNFS-e Nacional (gov.br) - XML
- The document itself. It is what gets signed with the issuer's A1 certificate, what the SEFAZ or the ADN authorizes, and what must be kept for five years. Everything else — PDF, email, screen — is a representation.
xmlReferencesEsquemas XML espelhadosSee in the API
Who takes part
- SEFAZ
- The state authorizer for NF-e. Each state runs its own, with its own uptime: one SEFAZ being down does not take the others with it, which is why contingency exists. Rejections come from here, with a numeric code and a reason.ReferencesPortal Nacional da NF-ePortal DF-e SVRSSee in the API
- ADN
- The national data environment for NFS-e. It centralizes issuance for the municipalities that adopted the national standard, replacing one integration per city hall with a single one. Municipalities that did not adopt it still run their own systems.ReferencesNFS-e Nacional (gov.br)NFS-e — documentação técnica
- Emitente
- Whoever issues the document. On stackin the issuer never travels in the request body: tax id, state registration, address, tax regime, certificate and environment are all resolved from the API key. That is deliberate — a leaked key cannot issue on another company's behalf.ReferencesCNPJ — Receita Federal
- Destinatário
- Whoever receives it. For NF-e the address is required and complete, including the IBGE municipality code; for NFS-e it is optional.
tax_idtakes a CPF or a CNPJ and tells them apart by length on its own.client_nametax_idrecipient_addressReferencesCódigos de município — IBGESee in the API
Fields and identifiers
- Chave de acesso
- 44 digits for NF-e, 50 for NFS-e. It is not random: it carries the state, the year and month, the issuer's tax id, the model, the series, the number, the issuance type and a check digit. It is how a document is consulted and cancelled — and what the DANFE's barcode encodes.
access_keyReferencesPortal Nacional da NF-eNotas Técnicas espelhadasSee in the API - Protocolo
- The number the authorizer returns when it accepts the document. It only exists after authorization: a rejected document has no protocol, which is why it comes back null while the status is not authorized.
protocolReferencesPortal Nacional da NF-e - Série e número
- Sequential numbering per issuer, per series and per model. It cannot have holes: if a number was burned and never became an authorized document, it has to be formally invalidated, or the SEFAZ will ask about it at an audit.
seriesnumberReferencesPortal Nacional da NF-eSee in the API - Preço unitário e valor da linha
unit_priceis the price of one unit;amountis the line's gross total, before discount and charges. Send either — sending both asserts they agree, and the API comparesquantity × unit_priceagainstamountbefore transmitting. In the XML they becomevUnCom(10 places) andvProd(2 places).items[].unit_priceitems[].amountitems[].product.quantityReferencesEsquemas XML espelhadosPortal Nacional da NF-eSee in the API- Encargos do item
- Discount, freight, insurance and other expenses belong to the item, not to the invoice. The item's total is
gross − discount + freight + insurance + other expenses, and the sum of these fields feeds thevDesc,vFrete,vSegandvOutrototals. A discount larger than the gross amount is refused before transmission.items[].product.discountitems[].product.freightitems[].product.insuranceitems[].product.other_expensesReferencesEsquemas XML espelhadosSee in the API - CFOP
- Four digits stating the nature of the operation: the first is the destination (5 inside the state, 6 outside, 7 abroad) and the other three the purpose — sale, return, shipment, processing. It decides how the state taxes the operation, so a wrong CFOP produces wrong tax, not a schema error.
items[].product.br.cfopReferencesAjuste SINIEF 07/05See in the API - NCM
- Eight digits classifying goods across Mercosur. It drives the IPI rate, ICMS-ST treatment and the import regime. stackin validates the format, never the choice: which NCM applies to your product is the issuer's fiscal decision.
items[].product.br.ncmReferencesNCM — Receita FederalSee in the API - CEST
- Seven digits, required only for goods under tax substitution. If the product is not in that regime the field is simply left out — sending a CEST for a product outside ST is grounds for rejection.
items[].product.br.cestReferencesConvênio ICMS 142/18 - Unidade comercial
- The unit the goods are sold in — UN, CX, KG, L. It is free text of up to 6 characters in the XML, not a closed list, but it has to agree with the quantity: 2 CX at R$ 120.00 is not the same as 2 UN at R$ 120.00 when the cargo is checked.
items[].product.unitReferencesEsquemas XML espelhados - GTIN
- The product's real GTIN, when it has one. When it does not, the XML carries the literal
SEM GTIN— which is what stackin sends if you omit the field. Inventing a number is worse than omitting it: the check digit is verified.items[].product.barcodeReferencesNotas Técnicas espelhadas - Código de serviço
- The item from the LC 116/2003 list —
1.07,7.02and so on. Every municipality breaks that list down its own way, so the same service can have a different sub-item per city. Without one, stackin uses the code from the company's fiscal profile.items[].service_codeReferencesLei Complementar 116/2003NFS-e — documentação técnicaSee in the API - CNPJ e CPF
- A CPF (11 digits) or a CNPJ (14). Since 2026-07-31 the CNPJ is alphanumeric: the first 12 characters may be letters, only the 2 check digits stay numeric. Validate length and shape, never a check-digit rule from an older revision — it rejects valid documents.
tax_idReferencesCNPJ — Receita FederalSee in the API - Código de município
- The 7-digit IBGE code for the municipality. Required on NF-e for both issuer and recipient, and it — not the city's name — is what the SEFAZ reads. A correctly spelled city with the wrong code is a rejection.
recipient_address.city_codeReferencesCódigos de município — IBGE
Events
- Cancelamento
- An event after authorization, with a legal window counted from it (24 hours in most states for NF-e) and a reason of at least 15 characters. After the window there is no cancellation: the way out is a return invoice. Cancelling does not erase the document, it records an event about it.
POST /invoices/{access_key}/cancelreasonReferencesPortal Nacional da NF-eNotas Técnicas espelhadasSee in the API - CC-e
- The electronic correction letter. It fixes what does not change value, tax, issuer or recipient — typically the description, transport data, additional information. NF-e only. Up to 20 letters per document, and each one replaces the last.
POST /invoices/{access_key}/correctioncorrectionReferencesPortal Nacional da NF-eNotas Técnicas espelhadasSee in the API - Inutilização
- Declares to the SEFAZ that a range of numbers never became a document — burned by a system failure, say. It is what stops a hole in the sequence from becoming an audit problem. It does not undo an authorized invoice: that is what cancellation is for.
POST /invoices/invalidationsnumber_startnumber_endReferencesPortal Nacional da NF-eSee in the API - Reemissão
- Resending a document that was rejected or failed in transit. It consumes a new number, because the previous one was burned. stackin stores the original attempt's items, so a reissue does not ask for the body again.
POST /invoices/{invoice_id}/reissueSee in the API - Rejeição
- The authorizer's answer refusing the document, with a numeric code and a reason. A rejection is not a network error or a bug: it is the tax authority saying the content is wrong. The code is what matters — 972, for instance, is a missing technical-responsible group.
statusdetailReferencesNotas Técnicas espelhadasPortal Nacional da NF-eSee in the API
Environments
- Homologação
- The authorizer's own test environment. A document issued there has no fiscal value and the recipient comes out as
NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL, as the tax authority requires. Use it freely: it is free and unlimited.ReferencesPortal Nacional da NF-eSee in the API - Produção
- The real environment. A document issued here has legal value, enters tax assessment and only leaves by cancellation within the window. The environment is fixed on the API key, not passed on the call — there is no issuing to production by flipping a parameter by mistake.ReferencesPortal Nacional da NF-eSee in the API
- Contingência
- The alternate path when the state's SEFAZ is unavailable: the document goes to a national environment (SVC-AN or SVC-RS, depending on the state) instead of waiting. It changes the issuance type inside the XML, so it is not merely a retry.
contingencyReferencesPortal DF-e SVRSNotas Técnicas espelhadas - data-source
- The public mirror of the official publications stackin tracks: technical notes, XML schemas and manuals for NF-e and NFS-e, swept every 6 hours, versioned and published as an Atom feed and a JSON manifest. It is what answers "did the layout change?" without opening a single portal.Referencesstackin-io/data-sourceNotas Técnicas espelhadasEsquemas XML espelhados