CLI para emissão de NFS-e (Nota Fiscal de Serviço Eletrônica) padrão ABRASF v2.04
nfe é um cliente de linha de comando para emitir, consultar e cancelar
NFS-e conforme o padrão ABRASF v2.04, usado por muitas prefeituras
brasileiras.
MVP funcional cobrindo cinco comandos: init, emit, query, cancel,
env e status. Emissão em lote e geração de DANFSe (PDF) estão fora do
escopo.
just build # gera ./bin/nfe
./bin/nfe --versionRequer Go 1.21+ (desenvolvido contra 1.26).
docker run --rm ghcr.io/caian-org/nfe:latest --help./bin/nfe init # cria ~/.nfews
# Edite ~/.nfews/config.toml com os dados do seu prestador, credenciais e os
# endpoints WSDL do seu município. Os comandos abaixo usam ~/.nfews/config.toml
# por padrão; use -c para apontar para outro caminho.
./bin/nfe status
./bin/nfe emit ~/.nfews/example-nota.toml --dry-run # valida sem chamar o WS
./bin/nfe emit ~/.nfews/example-nota.toml # emite de verdade
./bin/nfe query --numero 42
./bin/nfe cancel --numero 42 --codigo 1| Comando | Função |
|---|---|
init [caminho] |
Cria a estrutura do projeto: config.toml, example-nota.toml, README.md. Padrão ~/.nfews. |
emit <arquivo> |
Emite uma NFS-e a partir de um TOML. --dry-run gera e assina sem chamar o WS. --wait-timeout ajusta o timeout (padrão 60s). |
query |
Consulta NFS-e por --numero ou por --data-inicial/--data-final. |
cancel |
Cancela uma NFS-e autorizada: exige --numero e --codigo (1=erro emissão, 2=serviço não prestado, 3=erro processamento, 4=duplicidade). |
env <homologacao|producao> |
Alterna o ambiente ativo. |
status |
Mostra a configuração ativa. |
| Flag | Significado |
|---|---|
-c, --config |
Caminho do arquivo de configuração (padrão ~/.nfews/config.toml). |
--json |
Emite saída JSON ao invés de texto humano. |
ambiente = "homologacao"
[soap]
wsdl_homologacao = "https://teste.exemplo.com.br/abrasf/ws/nfs?wsdl"
wsdl_producao = "https://producao.exemplo.com.br/abrasf/ws/nfs?wsdl"
[prestador]
cnpj = "00000000000000"
inscricao_municipal = "000000"
razao_social = "EMPRESA EXEMPLO LTDA"
nome_fantasia = "EXEMPLO"
[prestador.endereco]
endereco = "RUA EXEMPLO"
numero = "100"
bairro = "CENTRO"
codigo_municipio = "1234567"
uf = "SP"
cep = "01234000"
[prestador.contato]
telefone = "1100000000"
email = "contato@exemplo.com.br"
[autenticacao]
usuario = "${NFE_USUARIO}"
senha = "${NFE_SENHA}"
[autenticacao.certificado]
path = "${NFE_CERT_PATH}" # caminho do seu A1 .pfx
senha = "${NFE_CERT_PASS}"
[configuracoes]
serie_rps = "A"
proximo_numero_rps = 1
codigo_municipio = "1234567"
aliquota_iss = 5.0O path do certificado pode ser absoluto ou relativo. Quando relativo,
é interpretado a partir do diretório do config.toml (ex.: se o
config.toml está em ~/.nfews/ e path = "./cert.pfx", o nfe
procura por ~/.nfews/cert.pfx independente de onde o comando foi
executado).
Referências ${VAR} e $VAR são expandidas contra as variáveis de ambiente
do processo. Variáveis não definidas permanecem como o literal ${VAR} no
config, fazendo a validação detectar valores ausentes.
Após cada emissão bem-sucedida, proximo_numero_rps é incrementado e o
config é reescrito atomicamente (arquivo temporário + rename) — seu contador
sequencial sobrevive a crashes durante a escrita.
O cliente descobre o endpoint SOAP, o namespace e o SOAPAction por
operação a partir do WSDL informado em [soap] (espelha o comportamento do
módulo soap do Node usado pelas implementações em TypeScript).
cmd/nfe -> main pequeno: monta root cobra, executa, sai
internal/cli -> comandos cobra (init, emit, query, cancel, env, status)
internal/config -> load/save TOML, expansão de env vars, validação
internal/nota -> tipo de entrada TOML da nota e validação
internal/abrasf -> tipos XML, builders, parser de resposta
internal/xmlsig -> loader PKCS#12 + XMLDSig (RSA-SHA1, C14N inclusivo)
internal/soap -> cliente SOAP 1.1 com mTLS + basic auth + auto-discovery do WSDL
internal/service -> orquestra Emit/Query/Cancel
internal/render -> renderizadores humano (tabelas coloridas) e JSON
internal/logging -> factory de slog handler (sem emojis, nunca em stdout)
testdata/golden -> envelopes XML comitados usados pelos testes do abrasf
A ordem dos campos em internal/abrasf/types.go segue o XSD do ABRASF —
reordenar campos produz XML que o WS rejeita.
just test # suite completa
just test-race # com -race
just cover # relatório de coberturaGoldens ficam em testdata/golden/. Para regenerar após uma mudança
intencional no XML:
go test ./internal/abrasf/... -updateInspecione o diff antes de comitar — mudanças nos goldens são mudanças no formato wire.
- Coloque seu certificado A1 (
.p12ou.pfx) em disco. - Exporte as variáveis referenciadas no
config.toml:export NFE_USUARIO=... export NFE_SENHA=... export NFE_CERT_PATH=/caminho/para/cert.pfx export NFE_CERT_PASS=...
- Aponte
[soap]para o WSDL de homologação do seu município. - Execute:
./bin/nfe -c config.toml status # confere a config ./bin/nfe -c config.toml emit nota.toml --dry-run ./bin/nfe -c config.toml emit nota.toml ./bin/nfe -c config.toml query --numero <retornado> ./bin/nfe -c config.toml cancel --numero <retornado> --codigo 1
Se o WS rejeitar com um erro de regra de negócio, a CLI imprime as entradas
de MensagemRetorno (código + mensagem + correção) e sai com código 0. Erros
de rede, TLS ou de configuração saem com código diferente de zero.
Na medida do permitido por lei, Caian Ertl renunciou a todos os
direitos autorais e direitos conexos a este trabalho. No espírito de
liberdade de informação, você é encorajado a clonar, modificar, distribuir,
compartilhar ou fazer o que quiser com este projeto! ^C ^V