foxnfe (Python SDK)
SDK oficial FOX NF-e para Python — emissão NF-e, NFSe, cancelamento, consulta e integração MCP.
Requisitos
- Python 3.9+
- requests
>=2.28
Instalação
pip install foxnfe
# ou
poetry add foxnfe
# ou
uv add foxnfe
Quick Start
from foxnfe import Client
client = Client(tenant_slug="minha-empresa")
# Autenticar
auth = client.login("email@empresa.com", "senha-segura")
print(f"Token: {auth.token}")
# Ou usar token existente
client = Client(tenant_slug="minha-empresa", token="seu-token-aqui")
# Ou via with_token (retorna nova instância)
authed = client.with_token("seu-token-aqui")
NF-e
from foxnfe import Client, NfeEmitRequest
client = Client(tenant_slug="minha-empresa", token="seu-token")
payload = NfeEmitRequest(
ambiente=2, # 2=homologação
certificate_id=1,
tomador={
"cnpj": "12345678000190",
"razao_social": "Empresa Tomadora Ltda",
"endereco": {
"logradouro": "Rua das Flores",
"numero": "100",
"municipio": "São Paulo",
"uf": "SP",
"cep": "01310100",
},
},
itens=[{
"codigo": "SRV001",
"descricao": "Serviço de consultoria",
"cfop": "5933",
"quantidade": 1,
"valor_unitario": 1000.00,
"valor_total": 1000.00,
}],
pagamentos=[{"forma": "01", "valor": 1000.00}],
total=1000.00,
)
result = client.nfe.emit(payload)
print(f"NF-e ID: {result['id']}")
# Aguardar autorização (polling automático)
nfe_autorizada = client.nfe.wait_for_authorization(result["id"])
print(f"Status: {nfe_autorizada.status}") # authorized
# Baixar XML
xml_bytes = client.nfe.xml(result["id"])
with open("nfe.xml", "wb") as f:
f.write(xml_bytes)
# Baixar DANFE PDF
pdf_bytes = client.nfe.pdf(result["id"])
with open("danfe.pdf", "wb") as f:
f.write(pdf_bytes)
# Cancelar
client.nfe.cancel(result["id"], "Cancelamento solicitado pelo cliente")
NFSe
from foxnfe import Client, NfseEmitRequest
client = Client(tenant_slug="minha-empresa", token="seu-token")
payload = NfseEmitRequest(
competencia="2026-09", # AAAA-MM
cnpj_prestador="12345678000190",
inscricao_municipal="123456",
razao_social_prestador="Minha Empresa Ltda", # opcional
descricao_servico="Desenvolvimento de software sob encomenda",
codigo_municipio_prestacao="3550308", # IBGE 7 dígitos
valor_servico=5000.00,
# informe cnae OU o trio abaixo
codigo_tributacao_nacional="01.03.01.00", # formato dd.dd.dd.dd
codigo_tributacao_municipal="0103",
aliquota_iss=2.0,
tomador={"cnpj": "98765432000110", "nome": "Cliente S.A."}, # cnpj OU cpf
prestador={"endereco": {
"logradouro": "Av. Paulista", "numero": "1000", "bairro": "Bela Vista",
"codigo_municipio": "3550308", "uf": "SP", "cep": "01310100",
}},
)
result = client.nfse.emit(payload) # também aceita um dict equivalente
nfse = client.nfse.get(result["nfse_id"]) # 202 {nfse_id, status: pending, message}
print(f"Número NFSe: {nfse.numero_nfse}")
# Consultar por RPS ou chave
client.nfse.consult_by_numero("00000001")
client.nfse.consult_by_chave("SP3550308202605010000000000001")
# Cancelar (justificativa 15..255) / Substituir (motivo 15..255 + campos de emissão)
client.nfse.cancel(result["nfse_id"], "Erro nos dados do tomador")
client.nfse.substitute(result["nfse_id"], payload, "Correção dos dados do tomador")
MCP (Model Context Protocol)
from foxnfe import Client
client = Client(tenant_slug="minha-empresa", token="seu-token")
# Inicializar sessão MCP
info = client.mcp.initialize()
print(f"MCP Server: {info['result']['serverInfo']['name']}")
# Listar tools
tools = client.mcp.list_tools()
for tool in tools:
print(f"{tool.name}: {tool.description}")
# Chamar uma tool
result = client.mcp.call_tool("emitir_nfe", {
"ambiente": 2,
"certificate_id": 1,
})
if result.get("result", {}).get("isError"):
print("Tool error:", result["result"]["content"][0]["text"])
else:
print("Tool result:", result["result"]["content"][0]["text"])
Tratamento de Erros
from foxnfe import Client
from foxnfe.exceptions import ApiException, AuthException, FoxNfeException
try:
client.nfe.emit(payload)
except AuthException as e:
# Token inválido ou expirado (401/403)
print(f"Auth error: {e}")
except ApiException as e:
# Erro da API (422, 500, etc.)
print(f"API error {e.status_code}: {e}")
print(f"Body: {e.response_body}")
except FoxNfeException as e:
# Timeout, erro de conexão, etc.
print(f"SDK error: {e}")
Uso com context manager
from foxnfe import Client
# Client usa requests.Session internamente (pode ser fechado manualmente)
client = Client(tenant_slug="minha-empresa", token="seu-token")
try:
result = client.nfe.emit(payload)
finally:
client._session.close()
Configuração avançada
client = Client(
tenant_slug="minha-empresa",
token="seu-token",
base_url="https://foxnfe.centralfox.online/api/v1", # host legado; padrão: https://www.foxnfe.com.br/api/v1
timeout=60.0,
)
Estrutura do pacote
foxnfe/
├── __init__.py # Exports públicos
├── client.py # Cliente HTTP principal
├── nfe.py # Módulo NF-e
├── nfse.py # Módulo NFSe
├── mcp.py # Módulo MCP
├── types.py # Dataclasses com tipagem
└── exceptions.py # Classes de erro
Links
1.3.0 — eventos, rejeições, homologação, RTC, cobertura NFS-e e suporte
ev = client.nfe_events
ev.ator_interessado(15, "11222333000181") # 110150
ev.insucesso_entrega(15, "2026-09-08T10:00:00-03:00", tp_motivo=1) # 110192
ev.inutilizar(serie=1, numero_inicial=10, numero_final=12, justificativa="Numeração pulada por falha do ERP")
ev.contratos(); ev.registrar_evento(15, "econf", {...}) # eventos por contrato (conciliação financeira, RTC…)
client.nfe.rejeicao("539"); client.nfe.homologacao_run(65) # rejeições explicadas / amostras simuladas
client.nfse.cobertura_municipio("2304400") # driver, operações e provas
client.rtc.verify_resolution("550e8400-e29b-41d4-a716-446655440000")
client.support.create_case("Webhook sem entrega desde ontem", priority="high")
Validação local (ids, dígitos, tamanhos, enums) antes do transporte; regra fiscal fica na API. NfeResource.rejection traz a rejeição classificada.
1.3.2 — correção do contrato NFS-e e URL base canônica
nfse.emit: corpo alinhado aoEmitNfseRequestda API (competencia,cnpj_prestador,inscricao_municipal,descricao_servico,codigo_municipio_prestacao,valor_servico,tomador,prestador.endereco+ opcionais).ambiente,certificate_ideservicosaíram do tipo — não existem no contrato NFS-e. Campos nulos não são enviados.nfse.cancel: enviajustificativa(15..255, validado antes do envio);motivosegue aceito como alias.nfse.substitute: enviamotivo(15..255) + campos de emissão;motivo_cancelamentosegue aceito como alias e não é enviado. Na substituição a API exigecodigo_tributacao_nacional,codigo_tributacao_municipalealiquota_iss(sem rota porcnae).- Respostas de emit/cancel/substitute são
{nfse_id, message}(202); a consulta usanfse_id. - URL base padrão:
https://www.foxnfe.com.br/api/v1(canônico). O host legadohttps://foxnfe.centralfox.online/api/v1continua respondendo e pode ser passado explicitamente.
Landing e Site IA — SEO 1.1.0 (11/09/2026)
Release files for foxnfe 1.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| foxnfe-1.3.2.tar.gz | 18.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| foxnfe-1.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.9 kB
Release files / foxnfe-1.3.2.tar.gz
| Download URL | foxnfe-1.3.2.tar.gz |
|---|---|
| Size | 18.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8bf8d5c1c9387b9b3e4e3f074b2504a97dd75849edbb1b6097ee1177e60ef3bf
|
|
BLAKE2b-256 checksum How to use checksums |
4cc25703d3308520f143fb7d18a0883945f556508ca67da5a934a050efbe9933
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / foxnfe-1.3.2-py3-none-any.whl
| Download URL | foxnfe-1.3.2-py3-none-any.whl |
|---|---|
| Size | 21.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
443d34ac1e61fc4d1da059f2e5903503ace01c7ad9fdb69b8f1de47414a91219
|
|
BLAKE2b-256 checksum How to use checksums |
d31c59ad257bedc379b26a0539f83157bb93f3c557f681978ba41ed82eabb27e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|