Skip to main content

Cliente Python para a NFS-e Nacional do Brasil (SEFIN) — assinatura, transmissão, consulta, cancelamento, DFe e DANFSe.

Project description

brans-nfe

PyPI version Python versions Downloads Downloads/month License: MIT Tests

Cliente Python para a NFS-e Nacional do Brasil (SEFIN/Receita Federal) — emissão, consulta, cancelamento, distribuição de DFe e DANFSe, com assinatura XMLDSIG, mTLS com certificado A1 ICP-Brasil e payloads compactados em gzip+base64.

A nfelib fornece os bindings do XSD oficial. A brans-nfe foca na conversa com o SEFIN: PKCS#12, cadeia ICP-Brasil, assinatura XMLDSIG, transporte mTLS, paginação de DFe, mapeamentos de enums e modelagem de input.

Recursos

  • ✅ Emissão de NFS-e a partir de DPS (POST /nfse)
  • ✅ Consulta de NFS-e por chave de acesso (GET /nfse/{chave})
  • ✅ Consulta/verificação de DPS por Id (GET /dps/{id}, HEAD /dps/{id})
  • ✅ Cancelamento com evento e101101 assinado (POST /nfse/{chave}/eventos)
  • ✅ Consulta de evento específico (GET /nfse/{chave}/eventos/{tipo}/{seq})
  • ✅ Download do DANFSe oficial (GET /danfse/{chave} no ADN)
  • ✅ Sincronização DFe (GET /contribuintes/DFe/{NSU}?cnpjConsulta=...)
  • ✅ Listagem de eventos de uma NFS-e (GET /contribuintes/NFSe/{chave}/Eventos)
  • Tomador estrangeiro (turistas, empresas internacionais): NIF, cNaoNIF (dispensado/não exigência), endereço exterior com país ISO
  • ✅ Carregamento de certificado A1 (.pfx/.p12) com extração de CNPJ do subject ou SAN ICP-Brasil
  • ✅ Resolução automática da cadeia ICP-Brasil a partir de bundle PEM
  • ✅ Modelos Pydantic v2 com validação (CEP, CNPJ, codigos IBGE, codigos LC 116)
  • ✅ Sanitização Latin-1 do xInfComp (en-dash, aspas curvas, emojis)
  • ✅ Patch automático do enum TstipoRetPiscofins da nfelib 2.5.2
  • ✅ Tipagem estrita (mypy-friendly), erros tipados

Instalação

pip install brans-nfe

Para gerar DANFSe não-oficial em PDF (auxiliar, quando o portal SEFIN está fora):

pip install "brans-nfe[danfse]"

Quick start

Emitir NFS-e

from datetime import date
from decimal import Decimal
from brans_nfe import (
    Ambiente, Certificado, NfseClient, NotaServico,
    Prestador, Tomador, Servico, Valores, Endereco,
    RegimeTributario, TributacaoIss,
)

certificado = Certificado.from_pfx_path("certificado.pfx", "senha-do-pfx")

client = NfseClient(
    certificado=certificado,
    ambiente=Ambiente.HOMOLOGACAO,
)

nota = NotaServico(
    serie_rps="1",
    numero_rps="42",
    data_competencia=date(2026, 5, 18),
    prestador=Prestador(
        cnpj=certificado.cnpj,
        razao_social=certificado.razao_social,
        regime_tributario=RegimeTributario.SIMPLES_NACIONAL,
        endereco=Endereco(
            codigo_municipio_ibge="3304557",
            cep="20010000",
            logradouro="Rua do Prestador",
            numero="100",
            bairro="Centro",
        ),
    ),
    tomador=Tomador(
        cpf_cnpj="98.765.432/0001-10",
        razao_social="CLIENTE TESTE SA",
        endereco=Endereco(
            codigo_municipio_ibge="3304557",
            cep="20010001",
            logradouro="Av. do Tomador",
            numero="200",
            bairro="Centro",
        ),
        email="financeiro@cliente.com",
    ),
    servico=Servico(
        codigo_tributacao_nacional="010101",
        codigo_municipio_prestacao="3304557",
        discriminacao="Servico de consultoria em TI",
    ),
    valores=Valores(
        valor_bruto=Decimal("1000.00"),
        valor_liquido=Decimal("950.00"),
    ),
    iss=TributacaoIss(
        aliquota=Decimal("5.00"),
        valor=Decimal("50.00"),
        base_calculo=Decimal("1000.00"),
    ),
)

resp = client.transmitir(nota)
print(resp.chave_acesso)
print(resp.id_dps)
print(resp.xml_nfse_retorno)

Emitir NFS-e para tomador estrangeiro

Caso 1: turista internacional contratando serviço spot no Brasil — sem documento fiscal:

from brans_nfe import Tomador, EnderecoExterior, MotivoSemNif

tomador = Tomador(
    motivo_sem_nif=MotivoSemNif.NAO_EXIGENCIA,
    razao_social="JOHN SMITH",
    endereco_exterior=EnderecoExterior(
        codigo_pais="US",
        codigo_postal="10001",
        cidade="New York",
        estado_provincia="NY",
        logradouro="5th Avenue",
        numero="350",
        bairro="Manhattan",
    ),
    email="john@example.com",
)

Caso 2: empresa estrangeira com NIF (Número de Identificação Fiscal):

tomador = Tomador(
    nif="PT123456789",
    razao_social="EMPRESA PORTUGUESA LDA",
    endereco_exterior=EnderecoExterior(
        codigo_pais="PT",
        codigo_postal="1000-001",
        cidade="Lisboa",
        estado_provincia="Lisboa",
        logradouro="Rua Augusta",
        numero="100",
        bairro="Baixa",
    ),
)

Códigos de MotivoSemNif: NAO_INFORMADO (0), DISPENSADO (1), NAO_EXIGENCIA (2). Use quando o tomador não tem identificação fiscal alguma.

Cancelar NFS-e

from brans_nfe import MotivoCancelamento

resp = client.cancelar(
    chave_acesso=resp.chave_acesso,
    motivo="Erro no preenchimento dos valores tributados",
    motivo_codigo=MotivoCancelamento.ERRO_EMISSAO,
)

Consultar e baixar DANFSe oficial

nfse = client.consultar(chave_acesso="33...50_digitos")
pdf_bytes = client.baixar_danfse(chave_acesso="33...50_digitos")

with open("danfse.pdf", "wb") as f:
    f.write(pdf_bytes)

Sincronizar DFe (notas recebidas)

resp = client.sincronizar_dfe(ultimo_nsu=0)
for item in resp.itens:
    print(item.nsu, item.chave_acesso, item.tipo_documento)
print("Proximo NSU:", resp.ultimo_nsu)

Recuperar de timeout: consultar DPS por Id

Se a transmissão deu timeout mas você quer descobrir se a NFS-e foi gerada:

if client.existe_dps(id_dps="DPS3304557..."):
    resp = client.consultar_dps(id_dps="DPS3304557...")
    print("Foi emitida:", resp.chave_acesso)

Construir DPS sem transmitir

Útil para preview, auditoria ou armazenamento prévio:

from brans_nfe import construir_dps, serializar_dps, assinar_xml

dps = construir_dps(nota, Ambiente.HOMOLOGACAO)
xml = serializar_dps(dps)
xml_assinado = assinar_xml(xml, certificado)

API

Modelos (Pydantic v2)

Modelo Descrição
NotaServico DPS completa: prestador, tomador, serviço, valores, ISS, PIS/COFINS, retenções
Prestador CNPJ + razão social + regime tributário + endereço
Tomador CPF/CNPJ ou NIF ou motivo_sem_nif + razão social + endereço opcional (nacional ou exterior)
Servico Código LC 116 (6 dígitos) + município prestação + discriminação
EnderecoNacional IBGE 7 dígitos + CEP 8 dígitos + logradouro + bairro (Endereco é alias)
EnderecoExterior País ISO (2 chars) + código postal + cidade + estado/província + logradouro + bairro
Valores Valor bruto, líquido, descontos condicional/incondicional
TributacaoIss Alíquota, valor, base, retenção (prestador/tomador/intermediário)
TributacaoPisCofins CST, alíquotas, valores, retidos
Retencoes IRRF, INSS, CSLL

Cliente

NfseClient(
    certificado: Certificado,
    ambiente: Ambiente = Ambiente.HOMOLOGACAO,
    ca_bundle: str | Path | None = None,
    chain_bundle: str | Path | None = None,
    timeout: int = 120,
    versao_aplicativo: str = "brans-nfe-0.1.0",
)
Método Endpoint Retorno
transmitir(nota) POST /nfse RespostaTransmissao
consultar(chave) GET /nfse/{chave} dict
consultar_dps(id) GET /dps/{id} RespostaConsultaDps
existe_dps(id) HEAD /dps/{id} bool
cancelar(chave, motivo) POST /nfse/{chave}/eventos RespostaEvento
consultar_evento(chave, codigo, seq) GET /nfse/{chave}/eventos/{tipo}/{seq} RespostaEvento
baixar_danfse(chave) GET /danfse/{chave} bytes
sincronizar_dfe(ultimo_nsu) GET /contribuintes/DFe/{NSU} RespostaDfe
listar_eventos_nfse(chave) GET /contribuintes/NFSe/{chave}/Eventos RespostaDfe

Erros

Todos derivam de BransNfeError:

  • CertificadoError, CertificadoExpiradoError, CertificadoSenhaInvalidaError
  • ValidacaoDpsError
  • AssinaturaXmlError
  • TransmissaoError, ConsultaError, CancelamentoError, DanfseIndisponivelError, SincronizacaoDfeError (todos com status_code e corpo)

Ambientes oficiais

Serviço Homologação Produção
SEFIN https://sefin.producaorestrita.nfse.gov.br/SefinNacional https://sefin.nfse.gov.br/SefinNacional
ADN https://adn.producaorestrita.nfse.gov.br https://adn.nfse.gov.br

O NfseClient resolve automaticamente com base no Ambiente.

Por que outra lib?

A nfelib é excelente — fornece os bindings gerados a partir do XSD oficial — mas é apenas o modelo de dados. Pra emitir realmente uma NFS-e Nacional você precisa de:

Etapa nfelib brans-nfe
Dataclasses do XSD (Dps, Tcserv, enums) reutiliza
Serializar dataclass → XML ✅ (via xsdata) reutiliza
Carregar PKCS#12 + extrair CNPJ ICP-Brasil
Resolver cadeia ICP-Brasil
Assinar XML-DSig (C14N + SHA1 + KeyInfo)
Gzip + base64 do payload
POST mTLS ao SEFIN
Consultar / Cancelar / Sincronizar DFe
Baixar DANFSe oficial
Patch de enum bugado da nfelib 2.5.2
Sanitização Latin-1 do xInfComp
Modelagem Pydantic pronta pra usar

Desenvolvimento

git clone https://github.com/badbrans/brans-nfe.git
cd brans-nfe

python -m venv venv
.\venv\Scripts\Activate.ps1     # Windows
source venv/bin/activate         # Linux/Mac

pip install -e ".[dev]"

pytest                           # 89 testes
pytest --cov=brans_nfe            # com coverage
black src tests
isort src tests
mypy src

Licença

MIT — Copyright (c) 2026 Raphael Brans

Disclaimer

Esta biblioteca é um projeto independente e não tem vínculo com a Receita Federal, SEFIN, ICP-Brasil ou Comitê Gestor da NFS-e Nacional. Use em produção por sua conta e risco, em conformidade com a legislação vigente.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

brans_nfe-0.2.0.tar.gz (23.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

brans_nfe-0.2.0-py3-none-any.whl (28.4 kB view details)

Uploaded Python 3

File details

Details for the file brans_nfe-0.2.0.tar.gz.

File metadata

  • Download URL: brans_nfe-0.2.0.tar.gz
  • Upload date:
  • Size: 23.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for brans_nfe-0.2.0.tar.gz
Algorithm Hash digest
SHA256 91b781f9ccead6e998325b5c9bcf2acb06921a0a6d39f62cfd9b7c43e7267178
MD5 38c1132c77ef8915b0fafc74e01432fa
BLAKE2b-256 824a2ff8b263e47982d5ab260365d2e8d3aadede3830e37abf28b722db72497f

See more details on using hashes here.

Provenance

The following attestation bundles were made for brans_nfe-0.2.0.tar.gz:

Publisher: publish.yml on badbrans/brans-nfe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file brans_nfe-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: brans_nfe-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 28.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for brans_nfe-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1227db7d25e175edbb5c0a3fee574a64fe2d180fcc1155645cebdfd657f05c4
MD5 e8ccea0772b4baa523cee317ad7a36cc
BLAKE2b-256 ed9f70e0fc779d9b6d2f6c5b8dec52fb76e31274920bd6dbaca6547bebf79e36

See more details on using hashes here.

Provenance

The following attestation bundles were made for brans_nfe-0.2.0-py3-none-any.whl:

Publisher: publish.yml on badbrans/brans-nfe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page