Skip to main content

PyNFSeNacional

Emissão de NFS-e pela API do Sistema Nacional (SEFIN) e geração do DANFSe — em Python.

Feito por um contador da GT Contabilidade, para contadores e desenvolvedores que precisam emitir nota fiscal de serviço no padrão nacional sem depender de robô de navegador nem da API de PDF do governo.

CI PyPI Python License: MIT Ruff Checked: mypy Status

✅ Lançado — v1.x. Em produção real desde junho de 2026: é o motor que emite as NFS-e de um escritório de contabilidade, mês após mês, para prestadores de vários municípios — centenas de notas autorizadas pelo SEFIN Nacional. O pipeline completo (config → certificado → DPS → assinatura → transporte mTLS → DANFSe) é validado byte a byte contra uma implementação de referência e coberto por testes. A responsabilidade pela nota é sempre do emitente: valide cada emissão.


Por que existe

Com o Sistema Nacional NFS-e virando o padrão do país — e a reforma tributária (IBS/CBS) passando por ele —, todo escritório de contabilidade precisa emitir NFS-e pelo padrão nacional. O ecossistema PHP já tem bibliotecas maduras para isso; o Python, não — falta uma solução turnkey, ponta a ponta. Este projeto preenche essa lacuna, integrando o que o ecossistema fiscal Python já tem de melhor e adicionando o que faltava (o transporte ao SEFIN nacional + o acabamento).

Duas confusões que este projeto já resolve

  1. Existem duas APIs do governo. A de emissão (SEFIN Nacional) recebe a DPS assinada e devolve a NFS-e — é viva e é o futuro. A de geração de PDF/DANFSe (ADN) está sendo descontinuada (NT-008/2026). Por isso, aqui o DANFSe é gerado localmente.
  2. ambGer não é ambiente. O indicador Produção/Homologação é o tpAmb, não o ambGer (toda nota nacional tem ambGer=2). Confundir os dois marca nota de produção como "sem validade".

✨ Destaques

  • 🧾 Emite NFS-e pela API oficial (SEFIN Nacional) com certificado A1 — sem robô de navegador.
  • 🖨️ DANFSe gerado localmente (PDF), antecipando o fim da API de PDF do governo.
  • 🔐 Assinatura XMLDSIG por biblioteca madura (erpbrasil.assinatura), validada byte a byte.
  • ✅ Validação fiscal antes de enviar — pega E0312/E0712/E1235… e CPF/CNPJ (mód-11) localmente.
  • 🔁 Idempotência nativa (verificarDps) — não duplica nota num reenvio, e a nota recuperada volta com o XML (dá para gerar o DANFSe).
  • ❌ Cancelamento direto (e101101) ou por análise fiscal (e101103), para os municípios que não aceitam o direto.
  • 🔎 Consulta pela chave e 📬 caixa postal DF-e: as notas emitidas, as recebidas como tomador e os eventos do CNPJ, por NSU.
  • 💰 Valor em Decimal (também aceita "1.262,90"), sem erro de arredondamento binário.
  • 🔒 Certificado do servidor conferido (mTLS nos dois sentidos).
  • 🧩 Núcleo enxuto e MIT-limpo; a geração de PDF é uma dependência opcional.
  • 🐍 Tipado (mypy --strict), testado (incl. golden contra a referência) e com CLI turnkey.

📦 Instalação

# núcleo: emite a NFS-e (sem gerar PDF)
pip install PyNFSeNacionalGT

# + geração local do DANFSe (PDF) — dependência opcional
pip install "PyNFSeNacionalGT[danfse]"

Requer Python 3.10+. No PyPI o pacote se chama PyNFSeNacionalGT (o nome PyNFSeNacional esbarra na proteção do PyPI por semelhança com outro projeto); o import continua pynfsenacional. Pin recomendado: PyNFSeNacionalGT>=1.2.0 — a 1.2.0 corrige o contador de nDPS que travava depois de uma resposta perdida (toda emissão seguinte voltava "já emitida") e traz cancelamento, consulta pela chave e a caixa postal DF-e. O histórico de cada versão está no CHANGELOG.


🚀 Quickstart

Em Python

from decimal import Decimal
from pynfsenacional import Emissor

emissor = Emissor("config/cliente.json")          # certificado A1 + dados do prestador

nota = emissor.emitir(                              # monta DPS → assina → envia ao SEFIN
    valor=Decimal("150.00"),                        # também aceita "150,00", 150 ou 150.0
    descricao="Sessão de psicoterapia",
    tomador={"cpf_cnpj": "00000000000", "nome": "Fulano de Tal"},
)

print(nota.emitida, nota.numero_nfse, nota.chave_acesso)
nota.danfse("nota.pdf")                             # gera o PDF do DANFSe localmente

Depois da emissão:

nota = emissor.consultar(chave)                     # a NFS-e (e o XML) pela chave; None se não existe

r = emissor.cancelar(chave, justificativa="Erro na emissão da nota fiscal", motivo=1)
# motivo: 1=Erro na Emissão · 2=Serviço não Prestado · 9=Outros
# município que não aceita o cancelamento direto (E0823): modo="analise"
print(r.ok, r.cancelada, r.erro_msg)

caixa = emissor.sincronizar_dfe(nsu=0)              # emitidas, recebidas e eventos do CNPJ
for doc in caixa.documentos:
    print(doc.nsu, doc.classificar(emissor.cfg.prestador.cnpj), doc.chave_acesso)
proximo_nsu = caixa.ultimo_nsu                      # guarde: a próxima leitura parte daqui

Pela linha de comando

nfse-nacional emitir config/cliente.json \
    --valor 150,00 --descricao "Sessão de psicoterapia" \
    --tomador-doc 00000000000 --tomador-nome "Fulano de Tal" \
    --ambiente homologacao \
    --pdf nota.pdf
nfse-nacional consultar config/cliente.json <chave> --pdf nota.pdf
nfse-nacional cancelar  config/cliente.json <chave> --justificativa "Erro na emissão da nota fiscal"
nfse-nacional dfe       config/cliente.json --nsu 0 --destino xmls/
Saída Significado
✅ emitida — nNFSe 13 · chave 3304… nota emitida; o nNFSe é atribuído pelo SEFIN
❌ não emitida: [E0312] … rejeitada pelo SEFIN, com o código do erro
❌ config inválida: … barrada antes do envio pela validação local

Os 00000000000 acima são placeholders: o tomador precisa de CPF/CNPJ válido (a lib confere o dígito mód-11 localmente). Sem tomador, a nota sai como consumidor final (omite <toma>).

Operação: o nDPS é um contador interno por prestador+ambiente, persistido em out/numero_<id>_<ambiente>.txt — quem atribui o nNFSe é o SEFIN. Reenviar a mesma DPS é idempotente (verificarDps): não duplica. Se a DPS daquele número já existe, a lib busca a nota e compara valor e tomador: é a mesma → devolve ja_emitida com o XML; é outra (contador atrasado) → pula o número. Quem passa numero= explícito controla a numeração. Para acompanhar o passo a passo, rode nfse-nacional -v emitir … (o -v vem antes do subcomando).


🔧 Configuração (passo a passo)

Cada prestador é descrito por um JSON puro. Comece copiando o exemplo anotado:

{
  "id": "exemplo",
  "nome_cliente": "EMPRESA EXEMPLO LTDA",
  "ambiente": "homologacao",            // homologacao (teste) | producao (nota real)

  "certificado": {                      // ★ certificado A1 do PRÓPRIO prestador (.pfx)
    "path": "certs/exemplo.pfx",        //   NUNCA versionar — fica fora do git
    "senha": "0000"
  },

  "prestador": {
    "cnpj": "00000000000000",           // ★ 14 dígitos
    "codigo_municipio": "0000000",      // ★ IBGE 7 díg do município do emitente
    "inscricao_municipal": null,        //   OPCIONAL — quem decide é o CNC, POR CNPJ (E0116 ×
                                        //   E0120). Sem IM no CNC: deixe null. Nunca "de enfeite"
    "regime": {                         // ★ regime tributário
      "opSimpNac": 3,                   //   1=Não Optante · 2=MEI · 3=Optante ME/EPP
      "regApTribSN": 1,                 //   só ME/EPP (Não Optante e MEI: omitido, E0162)
      "regEspTrib": 0
    }
    // nome/endereço do prestador NÃO entram aqui: o SEFIN puxa do cadastro (E0128/E0121)
  },

  "servico": {
    "codigo_municipio_prestacao": "0000000",  // ★ IBGE do local da prestação
    "cTribNac": "041601",               // ★ Código de Tributação NACIONAL (6 díg, LC116)
    "cTribMun": "001",                  //   desdobro municipal — obrigatório onde o município
                                        //   usa desdobro (senão E0312); município sem desdobro
                                        //   REJEITA o campo (E0315): deixe "" e ele é omitido
    "descricao_padrao": "Serviço Prestado",
    "tributos": {
      "pTotTribSN": "6.00",             // ★ se Simples ME/EPP: % efetiva do Simples Nacional
      "piscofins_cst": "08"             //   CST do PIS/COFINS: "08"=sem incidência (default),
                                        //   "00"=nenhum. Confira no XML do próprio contribuinte
      // "tpRetISSQN": 2,               //   ISS retido pelo tomador (por NOTA — §15)
      // "tpRetPisCofins": "0",         //   tipo de retenção do PIS/COFINS (NT 007 — §12)
      // "pTotTrib": {"pTotTribFed": "11.33", "pTotTribEst": "0", "pTotTribMun": "3"}
                                        //   Não Optante: % aproximado em 3 parcelas (§14)
    }
    // "cNBS": "120015000",             //   Item da NBS (9 díg) — Regime Regular (§14)
    // "ibscbs": {"cIndOp": "050101", "CST": "000", "cClassTrib": "000001", "indFinal": "0"}
                                        //   grupo IBS/CBS — obrigatório no Regime Regular (§8)
  }
}

O que cada prestador precisa fornecer

Dado Onde obter
Certificado A1 (.pfx) + senha do próprio prestador (anuência); renove antes de vencer
CNPJ cadastro
Código do município (IBGE) município de atuação do prestador
Regime (opSimpNac/regApTribSN) contabilidade (é Simples? MEI ou ME/EPP?)
cTribNac (6 díg) item da LC116 da atividade (mesmo código do portal)
cTribMun (desdobro) o que o município administra p/ aquele cTribNac (alguns não usam)
Inscrição Municipal o CNC do município, por CNPJ — não é "por cidade" (§10)
pTotTribSN (% Simples) alíquota efetiva do Simples (contabilidade)

🔒 Nada sensível vai para o git. O .pfx, as configs reais (config/) e os XML/PDF de notas são ignorados por padrão (ver .gitignore). Os dados de exemplo são fictícios.


🧩 Como funciona

Este pacote integra as libs maduras do ecossistema fiscal Python e escreve só o que faltava (o transporte ao SEFIN nacional + o acabamento). Ver docs/roadmap.md.

config (JSON)  →  montar DPS (XML)  →  assinar (XMLDSIG)  →  gzip+base64 → POST /nfse (mTLS)
                       │                     │                                    │
                    lxml            erpbrasil.assinatura                    SEFIN Nacional
                                                                                  │
                                                                            NFS-e (XML)
                                                                                  │
                                                                  render DANFSe local (PDF)
                                                                                  │
                                                                          BrazilFiscalReport
Peça Biblioteca Módulo
Montar/serializar o XML da DPS lxml dps.py
Assinatura digital XMLDSIG erpbrasil.assinatura assinatura.py
Ler o certificado A1 .pfx cryptography certificado.py
Transporte mTLS ao SEFIN requests + requests-pkcs12 + código próprio sefin.py
Gerar o DANFSe (PDF) BrazilFiscalReport danfse.py
Validação fiscal + CLI — config.py, cli.py

🗺️ Status e roadmap

✅ Implementado e validado · ⏳ próximo

  • ✅ Config + validação fiscal (E-codes, CPF/CNPJ mód-11)
  • ✅ Leitura do certificado A1 (.pfx)
  • ✅ Montagem da DPS — C14N idêntico, byte a byte, à referência PHP (golden)
  • ✅ Assinatura XMLDSIG (mesmo DigestValue do gabarito)
  • ✅ Transporte mTLS + idempotência — emissão real validada em homologação e produção
  • ✅ DANFSe local (PDF)
  • ✅ CLI turnkey + logging
  • ✅ Publicado no PyPI (PyNFSeNacionalGT)
  • ✅ Tomador completo: IM, endereço, telefone e e-mail no <toma> (v0.2.0)
  • ✅ Leiaute RTC 1.01 da DPS (NT 004 v2.0 / NT 007) — alinhado à revisão oficial do XSD (defensivo p/ o endurecimento das validações RTC)
  • ✅ MEI (opSimpNac=2) com DPS própria e CNPJ alfanumérico (NT 2025.001) — v0.4.0
  • ✅ Inscrição Municipal opcional (regra do CNC por CNPJ) e cTribMun omitido onde o município não usa — v0.5.0
  • ✅ Margem anti-E0008 no dhEmi e informações complementares (xInfComp) — v1.0.0
  • ⏳ Endurecimento a partir de mais emissões reais
  • ✅ Regime Regular (Não Optante — Lucro Presumido/Real): pTotTrib, tpRetPisCofins, Item da NBS e o grupo IBS/CBS (classificação: cIndOp, CST, cClassTrib) — v1.1.0
  • ✅ ISS retido pelo tomador (tpRetISSQN=2), com a recusa local de E0204/E0237 — v1.1.0
  • ⏳ Grupo IBS/CBS do Simples Nacional (obrigatório a partir de 01/01/2027, Ato Conjunto RFB/CGIBS nº 4/2026) e os casos ainda não cobertos do grupo: destinatário ≠ adquirente, compra governamental
  • ⏳ Tomador estrangeiro / sem documento; pAliq (ISS retido de ME/EPP, município não conveniado)
  • ✅ Cancelamento (e101101 direto / e101103 análise fiscal), consulta pela chave e distribuição DF-e por NSU; valor em Decimal; certificado do servidor conferido — v1.2.0
  • ⏳ Evento de substituição (e105102) e manifestação do tomador
  • ⏳ DANFSe: exibir o total aproximado de tributos do Simples (pTotTribSN, Lei 12.741) — hoje sai como "—" (o BrazilFiscalReport não lê esse campo)

Detalhes em docs/roadmap.md e CHANGELOG.md.


🧪 Desenvolvimento

git clone https://github.com/Gomes343/PyNFSeNacional.git
cd PyNFSeNacional
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"        # dev já inclui o extra [danfse]

pytest                          # testes (inclui o golden contra a referência)
ruff check .                    # lint
mypy                            # tipos (strict)

Como contribuir: CONTRIBUTING.md. Reportar vulnerabilidades: SECURITY.md.


🏛️ Origem

Esta biblioteca nasceu dentro da GT Contabilidade — escritório contábil que emite NFS-e pelo padrão nacional, mês após mês, para empresas espalhadas por municípios com regras diferentes entre si. Cada regra de docs/conhecimento-fiscal.md foi paga com nota real: emissão travada, mensagem críptica do SEFIN, distância entre o que a documentação diz e o que o município de fato aceita.

Esse conhecimento é vantagem competitiva e poderia ter ficado guardado. A GT preferiu publicá-lo sob licença MIT — a obrigatoriedade do Sistema Nacional chega para todo mundo ao mesmo tempo, e ninguém deveria precisar pagar duas vezes pela mesma descoberta. O que está aqui é a regra fiscal destilada e o código que a implementa; nunca dado de contribuinte.


Biblioteca para emissão de NFS-e. Use por sua conta e risco e valide cada emissão — a responsabilidade pela nota é sempre do contribuinte/emitente. Não é um produto fiscal homologado/certificado e não substitui orientação contábil. Sem garantia de qualquer tipo (ver LICENSE).

📄 Licença

MIT — ver LICENSE. O núcleo usa só dependências permissivas. A geração do DANFSe (opcional, [danfse]) usa a BrazilFiscalReport (LGPL-3.0), empregada como dependência — quem só emite não a instala.

🙏 Créditos

Construído sobre o trabalho da comunidade fiscal Python brasileira — Akretion/erpbrasil (erpbrasil.assinatura) e Engenere (BrazilFiscalReport).

Mantido pela GT Contabilidade, que bancou as emissões reais em que cada regra deste repositório foi descoberta e validada.

Metadata

Release files for PyNFSeNacionalGT 1.2.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 PyNFSeNacionalGT 1.2.0
File Size Uploaded Provenance Actions
pynfsenacionalgt-1.2.0.tar.gz 142.1 kB With provenance Details for pynfsenacionalgt-1.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for PyNFSeNacionalGT 1.2.0
File Interpreter ABI Platform Actions
pynfsenacionalgt-1.2.0-py3-none-any.whl Python 3 none any Details for pynfsenacionalgt-1.2.0-py3-none-any.whl

Total release size: 194.6 kB

Release files / pynfsenacionalgt-1.2.0.tar.gz

Download URL pynfsenacionalgt-1.2.0.tar.gz
Size 142.1 kB
Tags Source
SHA-256 checksum
How to use checksums
25db558c5c2eb04a745573bfcaafcb5e0ff2b2a8d3bfbd27889fe2315bf75856
BLAKE2b-256 checksum
How to use checksums
aeaa08cd18bd2289d52f3915380ae896ed52ca9f951f44b9981c390c8b1fdfef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 31, 2026.

Transparency log

Release files / pynfsenacionalgt-1.2.0-py3-none-any.whl

Download URL pynfsenacionalgt-1.2.0-py3-none-any.whl
Size 52.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6e60cf4853392b405b55b1a446f4adce6f98e599dc402b52a4645f8fa0a26c91
BLAKE2b-256 checksum
How to use checksums
a928c2d009adddba297348f75e61e0273aac698ef521652d5121f378ba0b5096
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 31, 2026.

Transparency log

Security for PyNFSeNacionalGT 1.2.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pynfsenacionalgt-1.2.0.tar.gz

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 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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