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.
✅ Lançado — v1.0. 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
- 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.
ambGernão é ambiente. O indicador Produção/Homologação é otpAmb, não oambGer(toda nota nacional temambGer=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. - 🧩 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 nomePyNFSeNacionalesbarra na proteção do PyPI por semelhança com outro projeto); o import continuapynfsenacional. Pin recomendado:PyNFSeNacionalGT>=0.5.0— a v0.1.0 tem o bug de ordem da<IM>(corrigido na 0.2.0), a 0.3.0 traz o leiaute RTC 1.01, a 0.4.0 o MEI e o CNPJ alfanumérico, e a 0.5.0 a Inscrição Municipal opcional de verdade (§10 do conhecimento fiscal).
🚀 Quickstart
Em Python
from pynfsenacional import Emissor
emissor = Emissor("config/cliente.json") # certificado A1 + dados do prestador
nota = emissor.emitir( # monta DPS → assina → envia ao SEFIN
valor=150.00,
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
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
| 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
00000000000acima 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 emout/numero_<id>_<ambiente>.txt— quem atribui onNFSeé o SEFIN. Reenviar a mesma DPS é idempotente (verificarDps): não duplica. Para acompanhar o passo a passo, rodenfse-nacional -v emitir …(o-vvem antes do subcomando).
🔧 Configuração (passo a passo)
Cada prestador é descrito por um JSON puro. Comece copiando o exemplo anotado:
- 📄
examples/config-exemplo.json— pronto para copiar (JSON puro). - 📝
examples/config-exemplo.jsonc— o mesmo, comentado campo a campo. - 📚 Schema completo em
docs/conhecimento-fiscal.md(§3).
{
"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 (roadmap) · 2=MEI · 3=Optante ME/EPP
"regApTribSN": 1,
"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
}
}
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
DigestValuedo 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
cTribMunomitido onde o município não usa — v0.5.0 - ✅ Margem anti-E0008 no
dhEmie informações complementares (xInfComp) — v1.0.0 - ⏳ Endurecimento a partir de mais emissões reais
- ⏳ Tomador estrangeiro / sem documento; não-optantes (Lucro Presumido/Real)
- ⏳ Grupo IBS/CBS na DPS — próxima prioridade. Obrigatório na NFS-e para o Regime Regular desde 01/10/2026 (sem rejeição até 31/12/2026) e para o Simples Nacional a partir de 01/01/2027 (Ato Conjunto RFB/CGIBS nº 4/2026); ainda não emitido
- ⏳ Eventos (cancelamento e substituição)
- ⏳ DANFSe: exibir o total aproximado de tributos do Simples (
pTotTribSN, Lei 12.741) — hoje sai como "—" (oBrazilFiscalReportnã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.
⚖️ Aviso legal
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.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pynfsenacionalgt-1.0.0.tar.gz | 108.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pynfsenacionalgt-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 143.9 kB
Release files / pynfsenacionalgt-1.0.0.tar.gz
| Download URL | pynfsenacionalgt-1.0.0.tar.gz |
|---|---|
| Size | 108.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b9b484232ebcf67212d44a8f485a9ded514e5ceeb33fffa5c4120cffececb38
|
|
BLAKE2b-256 checksum How to use checksums |
619d7621ee9189514dd62b10fa3d2c08d8f94702371bf88153c1af4cc39dafb8
|
| 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 14, 2026.
Transparency logRelease files / pynfsenacionalgt-1.0.0-py3-none-any.whl
| Download URL | pynfsenacionalgt-1.0.0-py3-none-any.whl |
|---|---|
| Size | 35.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8e5774e78d56a5fbffeb3ac5ba23ab05a63c26a3a7031c226f068af2bf248a5f
|
|
BLAKE2b-256 checksum How to use checksums |
70048192bd548170298a46b0dcc510406ca9c136ecd8f213f526e64d3d3f158e
|
| 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 14, 2026.
Transparency log