Skip to main content

nfelib — the Python library for Brazilian electronic invoicing

PyPI Downloads

nfelib covers the full life-cycle of the Brazilian electronic fiscal documents (DF-e): parse, build, sign, validate, transmit to the SEFAZ webservices and print:

Document Parse / build / sign / validate Transmission PDF
NF-e / NFC-e (invoices) yes SOAP: authorize, cancel, CC-e, inutilização, consultation, MD-e events, DistDFe DANFE
CT-e (freight) yes SOAP: authorize (synchronous) DACTE
MDF-e (manifest) yes SOAP: authorize (synchronous), cancel, encerramento, consultation DAMDFE
NFS-e (national standard) yes REST: DPS submission, NFS-e and event consultation, cancelling DANFSE
NF3e / NFCom (energy / telecom) yes — —
BP-e (passenger transport) yes — —

Our goal is to make nfelib the default Python library for electronic invoicing in Brazil. The library is used extensively by the OCA/l10n-brazil localization for Odoo (ERP). nfelib delegates the PDF rendering to the free BrazilFiscalReport project, maintained by friends of nfelib, which draws DANFE, DACTE, DACTE-OS and DAMDFE.

Why nfelib?

  • Simple and reliable. Other libraries maintain tens of thousands of lines of hand-written code to do what nfelib does with a few lines: it generates its databindings from the official Fazenda XSD packages with xsdata, an extremely well written and tested data binding library. nfelib itself round-trip tests every document type it supports.
  • Complete and current. Because regenerating bindings is trivial, nfelib tracks every Fazenda release package for NF-e, NFS-e, CT-e, MDF-e and BP-e — documents and their events — and its test suite detects when a new schema package is published.
  • Everything in one place. Bindings, XML signing (A1 certificates), schema validation, SOAP transmission clients and PDF printing compose into a single pipeline; you no longer need to glue several libraries together.

nfelib focuses on electronic invoicing. Its generator can technically bind any official XSD package, but we deliberately scope support to the DF-e schemas for now so they stay complete and battle-tested.

Installation

pip install nfelib

Optional features (install only what you need):

pip install nfelib[sign]   # XML signing with A1 certificates
pip install nfelib[pdf]    # PDF printing (BrazilFiscalReport)
pip install nfelib[soap]   # SOAP transmission clients (NF-e, CT-e, MDF-e)
pip install nfelib[nfse]   # REST client for the national NFS-e (ADN)

Usage

NF-e

>>> # Parse an NF-e:
>>> from nfelib.nfe.bindings.v4_0.proc_nfe_v4_00 import NfeProc
>>> nfe_proc = NfeProc.from_path("nfelib/nfe/samples/v4_0/leiauteNFe/NFe35200159594315000157550010000000012062777161.xml")
>>> # (from_xml(xml) also works)
>>>
>>> nfe_proc.NFe.infNFe.emit.CNPJ
'59594315000157'
>>> nfe_proc.NFe.infNFe.emit.enderEmit.UF.value
'SP'
>>>
>>> # Serialize an NF-e:
>>> nfe_proc.to_xml()
'<?xml version="1.0" encoding="UTF-8"?>\n<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> [...]'
>>>
>>> # Build an NF-e from scratch:
>>> from nfelib.nfe.bindings.v4_0.nfe_v4_00 import Nfe
>>> nfe = Nfe(infNFe=Nfe.InfNfe(emit=Nfe.InfNfe.Emit(xNome="My Company", CNPJ="59594315000157")))
>>>
>>> # Validate the XML against the official schemas:
>>> nfe.validate_xml()
["Element '{http://www.portalfiscal.inf.br/nfe}infNFe': The attribute 'versao' is required but missing.", ...]

Sign the XML of a document with an A1 certificate (erpbrasil.assinatura, works with every document type):

>>> with open(path_to_your_pkcs12_certificate, "rb") as pkcs12_buffer:
...     pkcs12_data = pkcs12_buffer.read()
>>> signed_xml = nfe.sign_xml(xml, pkcs12_data, cert_password, nfe.NFe.infNFe.Id)

Print the DANFE PDF with BrazilFiscalReport — which also prints the CT-e (DACTE/DACTE-OS) and the MDF-e (DAMDFE):

>>> pdf_bytes = nfe.to_pdf()
>>> # Or sign and print at once:
>>> pdf_bytes = nfe.to_pdf(
...     pkcs12_data=cert_data,
...     pkcs12_password=cert_password,
...     doc_id=nfe.NFe.infNFe.Id,
... )

NFS-e (national standard)

>>> # Parse an NFS-e:
>>> from nfelib.nfse.bindings.v1_0.nfse_v1_00 import Nfse
>>> nfse = Nfse.from_path("alguma_nfse.xml")
>>>
>>> # Serialize an NFS-e:
>>> nfse.to_xml()
>>> # Parse a DPS:
>>> from nfelib.nfse.bindings.v1_0.dps_v1_00 import Dps
>>> dps = Dps.from_path("nfelib/nfse/samples/v1_0/GerarNFSeEnvio-env-loterps.xml")

MDF-e

>>> # Parse an MDF-e:
>>> from nfelib.mdfe.bindings.v3_0.mdfe_v3_00 import Mdfe
>>> mdfe = Mdfe.from_path("nfelib/mdfe/samples/v3_0/ComPagtoPIX_41210780568835000181580010402005751006005791-procMDFe.xml")
>>>
>>> # Serialize an MDF-e:
>>> mdfe.to_xml()

CT-e

>>> # Parse a CT-e:
>>> from nfelib.cte.bindings.v4_0.cte_v4_00 import Cte
>>> cte = Cte.from_path("nfelib/cte/samples/v4_0/43120178408960000182570010000000041000000047-cte.xml")
>>>
>>> # Serialize a CT-e:
>>> cte.to_xml()

BP-e

>>> # Parse a BP-e:
>>> from nfelib.bpe.bindings.v1_0.bpe_v1_00 import Bpe
>>> bpe = Bpe.from_path("algum_bpe.xml")
>>>
>>> # Serialize a BP-e:
>>> bpe.to_xml()

NFS-e transmission (REST)

The national NFS-e system exposes a REST API (ADN) instead of SOAP. The client signs, GZip+Base64 packs the DPS and posts it over mutual TLS; install it with pip install nfelib[nfse].

from nfelib.nfse.client.v1_0.nfse import NfseClient

client = NfseClient(
    ambiente="2",              # 1=production, 2=production restrita (homologation)
    pkcs12_data=pkcs12_bytes,  # decoded content of the A1 certificate (.pfx)
    pkcs12_password="password",
)

ret = client.envia_dps(dps)                    # POST /nfse -> generates the NFS-e
ret.body["chaveAcesso"]
ret = client.consulta_nfse(chave)              # GET /nfse/{chaveAcesso}
ret = client.consulta_dps(dps_id)              # GET /dps/{id}
ret = client.cancela_documento(chave, evento)  # POST /nfse/{chaveAcesso}/eventos
ret = client.consulta_evento(chave, tipo_evento, num_seq)

The certificate may be given as raw PFX bytes, base64 text (like an Odoo Binary field) or a path to a .pfx file.

SOAP transmission (BETA)

nfelib ships transmission clients that sign and transmit documents directly to the SEFAZ webservices, over brazil-fiscal-client (mTLS with your A1 certificate). Install with pip install nfelib[soap].

from nfelib.nfe.client.v4_0.nfe import NfeClient
from nfelib.nfe.client.v4_0.nfce import NfceClient
from nfelib.nfe.client.v4_0.mde import MdeClient
from nfelib.cte.client.v4_0.cte import CteClient
from nfelib.mdfe.client.v3_0.mdfe import MdfeClient

client = NfeClient(
    ambiente="2",                # 1=production, 2=homologation
    uf="35",                     # IBGE code of the UF (for the SOAP header)
    pkcs12_data=pkcs12_bytes,    # decoded content of the A1 certificate (.pfx)
    pkcs12_password="password",
    wrap_response=True,          # returns a WrappedResponse (envio_xml, resposta, retorno)
)

processo = client.processar_lote([nfe])             # NF-e / NFC-e (async, with receipt polling)
processo = client.envia_documento(cte)              # CT-e  (CTeRecepcaoSincV4, synchronous)
processo = client.envia_documento(mdfe)             # MDF-e (MDFeRecepcaoSinc, synchronous)
processo = client.cancela_documento(...)            # MDF-e / NF-e cancellation event
processo = client.enviar_cce(chave, correcao)       # NF-e carta de correcao event
ret = client.consulta_documento(chave)              # NF-e/CT-e/MDF-e consultation

# Manifestacao do Destinatario (MD-e) events go to the Ambiente Nacional:
mde = MdeClient(ambiente="2", uf="35", pkcs12_data=pkcs12_bytes,
                pkcs12_password="password", wrap_response=True)
ret = mde.ciencia_da_operacao(chave, cnpj_cpf)
ret = mde.confirmacao_da_operacao(chave, cnpj_cpf)
ret = mde.desconhecimento_da_operacao(chave, cnpj_cpf)
ret = mde.operacao_nao_realizada(chave, cnpj_cpf, justificativa)

Support status (BETA, API may change):

Document Authorization Cancellation / events
NF-e / NFC-e yes cancel, CC-e, inutilizacao
CT-e yes (synchronous) not yet
MDF-e yes (synchronous) cancel, encerramento

The same clients power the DF-e distribution service (NFeDistribuicaoDFe, polling the documents sent to your CNPJ) and the Manifestacao do Destinatario events used by the OCA/l10n-brazil localization for Odoo.

Because the bindings, signing and transmission are all pure Python and serializable, nfelib can also be embedded behind a REST API (FastAPI, Odoo...) to offer electronic invoicing as a service.

Development / tests

Run the tests:

pytest

Update the bindings:

  1. download the new schema package zip and update nfelib/<nfe|nfse|cte|mdfe|bpe>/schemas/<version>/

  2. regenerate the bindings of one schema package, e.g. the NF-e:

    xsdata generate nfelib/nfe/schemas/v4_0 --package nfelib.nfe.bindings.v4_0
    # or ./generate_bindings.py nfe
    

Regenerate all bindings with xsdata:

./generate_bindings.py all

The exact source package of every binding directory is documented in CHANGELOG_SCHEMAS.md and injected into the generated files.

Schema versions and folders

nfelib uses only 2 digits to characterize a version. This was decided after observing that the Fazenda never uses the third digit, and that changing the second digit is already a major change. So any schema change that does not change the first nor the second digit of the schema version goes into the same folder and supersedes the previous version, assuming that it is possible to use the newer schema instead of the old one (for example, an NF-e 4.00 package 9j (NT 2022.003 v.1.00b) can be read with the bindings of the NF-e 4.00 package 9k (NT 2023.001 v.1.20)).

On the contrary, if there is a major change affecting the first 2 digits, as with NF-e 3.0 and NF-e 3.1 or NF-e 3.1 and NF-e 4.0, it will also be possible to support the various versions at the same time using different folders. It would be possible, for example, to issue the future NF-e 5.0 and still import an NF-e 4.0.

Credits

nfelib builds on the work of other open source projects of the Brazilian community:

  • erpbrasil.assinatura — used behind the façade to sign the XML documents with A1 certificates.
  • BrazilFiscalReport — used behind the façade to print the DANFE, DACTE, DACTE-OS and DAMDFE PDFs.
  • erpbrasil.edoc — the historical transmission library; it was the source of inspiration for the SOAP transmission clients.

Thanks to all the contributors:

Contributors

Metadata

Release files for nfelib 3.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nfelib 3.0.0
File Size Uploaded
nfelib-3.0.0.tar.gz 846.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nfelib 3.0.0
File Interpreter ABI Platform
nfelib-3.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.1 MB

Release files / nfelib-3.0.0.tar.gz

Download URL nfelib-3.0.0.tar.gz
Size 846.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d37b6fc4c7b0a9499f14ba1b9c99c480f9f8856840026a541a25be67d0f802ac
BLAKE2b-256 checksum
How to use checksums
06e4d8caa1c935b93c9e07ee5c345dd0a223e425068f07aa774e3305eadd5bb3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / nfelib-3.0.0-py3-none-any.whl

Download URL nfelib-3.0.0-py3-none-any.whl
Size 1.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
e59b0a03474ed208b5a0e715b6419b0b18349635b0e4484fcc9ff1db4ec6c2f1
BLAKE2b-256 checksum
How to use checksums
31baf45f563d3bc050eb34cbe833929a4ac0ed6e902ce2cd2410ccd4c2e42635
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

3.0.0 This release

2 release files

2.6.0

2 release files

2.5.3

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.1

2 release files

2.0.7

2 release files

2.0.6

1 release file

2.0.5

1 release file

2.0.4

1 release file

2.0.3

1 release file

2.0.2

1 release file

2.0.1

1 release file

1.3.1

1 release file

1.3.0

1 release file

1.2.2

1 release file

1.2.0

2 release files

1.1

2 release files

1.0

2 release files

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page