fiscal-rsfiscal-rs

SEFAZ: Protocolo e Serviços

Deep dive no ciclo de vida da requisição, catálogo de serviços, resolução de URLs por estado e parsing de respostas SOAP

Visão Geral

A SEFAZ (Secretaria da Fazenda) é o webservice da autoridade tributária brasileira responsável pela autorização, consulta e gerenciamento de documentos fiscais eletrônicos (NF-e/NFC-e). O crate fiscal-sefaz implementa toda a comunicação com esses webservices utilizando SOAP 1.2 sobre HTTPS com TLS mútuo (certificado digital A1).

Cada estado brasileiro possui seu próprio autorizador SEFAZ ou delega para uma SEFAZ Virtual (SVRS ou SVAN). O fiscal-sefaz abstrai completamente essa complexidade — basta informar a UF e o ambiente.

Módulos do crate

MóduloResponsabilidade
clientClient HTTP async com mTLS via reqwest
soapConstrução do envelope SOAP 1.2
servicesMetadados SOAP de cada serviço (método, operação, versão)
urlsResolução de URLs por estado, serviço e ambiente
request_buildersConstrução do XML de requisição para cada operação
response_parsersParsing das respostas XML da SEFAZ

Ciclo de Vida da Requisição

O fluxo completo de uma requisição à SEFAZ segue quatro etapas principais: construir o XML de requisição, encapsulá-lo em um envelope SOAP, enviar via HTTPS com mTLS, e parsear a resposta.

Loading diagram...

Etapa 1 — Construção do XML de Requisição

Os request_builders geram o XML interno de cada operação, conforme o schema da SEFAZ. Cada builder recebe os parâmetros da operação e retorna uma String XML.

use fiscal_sefaz::request_builders::build_status_request;
use fiscal_core::types::SefazEnvironment;

let xml = build_status_request("SP", SefazEnvironment::Homologation);
// Gera: <consStatServ xmlns="..." versao="4.00">
//         <tpAmb>2</tpAmb><cUF>35</cUF><xServ>STATUS</xServ>
//       </consStatServ>

Etapa 2 — Encapsulamento SOAP

O módulo soap encapsula o XML da requisição em um envelope SOAP 1.2 com os headers exigidos pela SEFAZ:

<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Header>
    <nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/{operation}">
      <cUF>{codigo_ibge}</cUF>
      <versaoDados>{versao}</versaoDados>
    </nfeCabecMsg>
  </soap12:Header>
  <soap12:Body>
    <nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/{operation}">
      {request_xml}
    </nfeDadosMsg>
  </soap12:Body>
</soap12:Envelope>

O header SOAP Content-Type também inclui a SOAP Action, construída no formato:

application/soap+xml;charset=utf-8;action="http://www.portalfiscal.inf.br/nfe/wsdl/{operation}/{method}"

Etapa 3 — Envio via mTLS

O SefazClient utiliza reqwest com identidade PKCS#12 (certificado A1) para autenticação mTLS. O TLS 1.2 é o mínimo exigido pela SEFAZ.

use fiscal_sefaz::client::SefazClient;

let pfx = std::fs::read("certificado.pfx").unwrap();
let client = SefazClient::new(&pfx, "senha")?;

Timeouts padrão:

  • Conexão: 30 segundos
  • Requisição completa: 90 segundos (horários de pico podem ser lentos)

Etapa 4 — Parsing da Resposta

Os parsers removem automaticamente o envelope SOAP e prefixos de namespace (nfe:, nfeResultMsg:) da resposta, extraindo as informações relevantes em structs tipadas.

use fiscal_sefaz::response_parsers::parse_autorizacao_response;

let resp = parse_autorizacao_response(&raw_xml)?;
println!("Status: {} — {}", resp.status_code, resp.status_message);
if let Some(prot) = &resp.protocol_number {
    println!("Protocolo: {prot}");
}

Catálogo de Serviços

O enum SefazService define todos os serviços disponíveis, cada um com seus metadados SOAP fixos (método, operação WSDL, versão do schema):

Loading diagram...

Tabela Completa de Metadados

ServiçoOperação WSDLMétodo SOAPVersãoChave URL
StatusServicoNFeStatusServico4nfeStatusServicoNF4.00NfeStatusServico
AutorizacaoNFeAutorizacao4nfeAutorizacaoLote4.00NfeAutorizacao
RetAutorizacaoNFeRetAutorizacao4nfeRetAutorizacaoLote4.00NfeRetAutorizacao
ConsultaProtocoloNFeConsultaProtocolo4nfeConsultaNF4.00NfeConsultaProtocolo
InutilizacaoNFeInutilizacao4nfeInutilizacaoNF4.00NfeInutilizacao
RecepcaoEventoNFeRecepcaoEvento4nfeRecepcaoEvento1.00RecepcaoEvento
DistribuicaoDFeNFeDistribuicaoDFenfeDistDFeInteresse1.01NfeDistribuicaoDFe
ConsultaCadastroCadConsultaCadastro4consultaCadastro2.00NfeConsultaCadastro

Cada variante expõe seus metadados via SefazService::meta():

use fiscal_sefaz::services::SefazService;

let meta = SefazService::Autorizacao.meta();
assert_eq!(meta.method, "nfeAutorizacaoLote");
assert_eq!(meta.operation, "NFeAutorizacao4");
assert_eq!(meta.version, "4.00");

Resolução de URLs por Estado

A SEFAZ brasileira não é um servidor centralizado. Cada estado possui seu próprio autorizador ou delega para uma SEFAZ Virtual. O módulo urls mapeia cada UF ao autorizador correto e resolve a URL do endpoint para cada serviço e ambiente.

Mapeamento de Autorizadores

AutorizadorEstados
AMAmazonas
BABahia
GOGoiás
MGMinas Gerais
MSMato Grosso do Sul
MTMato Grosso
PEPernambuco
PRParaná
RSRio Grande do Sul
SPSão Paulo
SVANMaranhão (MA)
SVRSAC, AL, AP, CE, DF, ES, PA, PB, PI, RJ, RN, RO, RR, SC, SE, TO

Os 17 estados que não possuem autorizador próprio utilizam a SVRS (SEFAZ Virtual do Rio Grande do Sul). O Maranhão é o único estado que utiliza a SVAN (SEFAZ Virtual do Ambiente Nacional).

Ambientes

Cada autorizador expõe endpoints separados para produção e homologação:

AmbienteSefazEnvironmentPrefixo típico da URL
ProduçãoProductionnfe.sefaz.XX.gov.br
HomologaçãoHomologationhomnfe.sefaz.XX.gov.br ou homologacao.nfe...

Uso da API

use fiscal_sefaz::urls::get_sefaz_url;
use fiscal_core::types::SefazEnvironment;

// Autorização em SP (produção)
let url = get_sefaz_url("SP", SefazEnvironment::Production, "NfeAutorizacao")?;
// → "https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx"

// Status em AL (via SVRS, homologação)
let url = get_sefaz_url("AL", SefazEnvironment::Homologation, "NfeStatusServico")?;
// → "https://nfe-homologacao.svrs.rs.gov.br/ws/NfeStatusServico/NfeStatusServico4.asmx"

A função retorna FiscalError::InvalidStateCode para UFs inválidas e FiscalError::XmlGeneration para nomes de serviço desconhecidos.

Construtores de Requisição

O módulo request_builders fornece funções para construir o XML de cada operação. Todos seguem o padrão de receber parâmetros da operação e retornar uma String com o XML pronto.

Verificação de Status

Verifica se o serviço da SEFAZ está operacional para uma determinada UF:

use fiscal_sefaz::request_builders::build_status_request;

let xml = build_status_request("SP", SefazEnvironment::Production);
// → <consStatServ xmlns="..." versao="4.00">
//     <tpAmb>1</tpAmb><cUF>35</cUF><xServ>STATUS</xServ>
//   </consStatServ>

Autorização de NF-e

Envia uma NF-e assinada para autorização. O XML assinado é encapsulado em um envelope <enviNFe>:

use fiscal_sefaz::request_builders::build_autorizacao_request;

let xml = build_autorizacao_request(&signed_nfe_xml, "123456", true, false);
// sync=true → indSinc=1 (processamento síncrono, resultado imediato)

Consulta por Chave de Acesso

Consulta o status de uma NF-e pela chave de acesso de 44 dígitos:

use fiscal_sefaz::request_builders::build_consulta_request;

let xml = build_consulta_request("35240100000000000100550010000000011000000019", env);

Consulta de Recibo

Consulta o resultado de um lote enviado de forma assíncrona (indSinc=0):

use fiscal_sefaz::request_builders::build_consulta_recibo_request;

let xml = build_consulta_recibo_request("351000000123456", env);

Inutilização de Numeração

Inutiliza uma faixa de números que foram pulados e não serão utilizados:

use fiscal_sefaz::request_builders::build_inutilizacao_request;

let xml = build_inutilizacao_request(
    24,                          // ano (2 dígitos)
    "12345678000199",            // CNPJ
    "55",                        // modelo (55=NF-e, 65=NFC-e)
    1,                           // série
    100,                         // número inicial
    110,                         // número final
    "Falha no sistema de emissão", // justificativa
    SefazEnvironment::Production,
    "SP",
);

Cancelamento

Cancela uma NF-e previamente autorizada:

use fiscal_sefaz::request_builders::build_cancela_request;

let xml = build_cancela_request(
    "35240100000000000100550010000000011000000019", // chave de acesso
    "135240000012345",                              // número do protocolo
    "Erro na emissão do documento fiscal",          // justificativa (mín. 15 chars)
    1,                                               // sequência do evento
    SefazEnvironment::Production,
    "12345678000199",                                // CNPJ
);

Carta de Correção (CC-e)

Envia uma correção textual para uma NF-e autorizada:

use fiscal_sefaz::request_builders::build_cce_request;

let xml = build_cce_request(
    "35240100000000000100550010000000011000000019",
    "Razão social do destinatário correto: Empresa XYZ Ltda",
    1,  // nSeqEvento (incrementa a cada correção na mesma NF-e)
    SefazEnvironment::Production,
    "12345678000199",
);

Manifestação do Destinatário

Registra eventos de manifestação do destinatário sobre notas recebidas:

use fiscal_sefaz::request_builders::build_manifesta_request;

let xml = build_manifesta_request(
    &access_key,
    "210200",      // Confirmação da Operação
    None,          // justificativa (obrigatória apenas para 210240)
    1,
    env,
    &tax_id,
);

Distribuição de DF-e

Consulta documentos fiscais distribuídos pelo ambiente nacional:

use fiscal_sefaz::request_builders::build_dist_dfe_request;

// Por último NSU
let xml = build_dist_dfe_request("SP", "12345678000199", None, None, env);

// Por chave de acesso específica
let xml = build_dist_dfe_request("SP", "12345678000199", None, Some(&access_key), env);

Consulta Cadastral

Consulta o cadastro de contribuintes por CNPJ, CPF ou Inscrição Estadual:

use fiscal_sefaz::request_builders::build_cadastro_request;

let xml = build_cadastro_request("SP", "CNPJ", "12345678000199");

Tipos de Evento

Os constantes de tipo de evento (tpEvento) estão definidas no módulo request_builders::event_types:

CódigoConstanteDescrição
110110CCECarta de Correção Eletrônica
110111CANCELLATIONCancelamento
210200CONFIRMATIONConfirmação da Operação
210210AWARENESSCiência da Operação
210220UNKNOWN_OPERATIONDesconhecimento da Operação
210240OPERATION_NOT_PERFORMEDOperação não Realizada

Todos os eventos seguem a mesma estrutura XML interna <envEvento>, com variações apenas nos campos de <detEvento>.

Parsing de Respostas

O módulo response_parsers fornece parsers tipados para as respostas mais comuns:

Structs de Resposta

AuthorizationResponse — resposta de autorização (retEnviNFe):

CampoTipoDescrição
status_codeStringCódigo de status (cStat)
status_messageStringMensagem descritiva (xMotivo)
protocol_numberOption<String>Número do protocolo (nProt)
protocol_xmlOption<String>Fragmento XML do <protNFe>
authorized_atOption<String>Timestamp da autorização (dhRecbto)

StatusResponse — resposta de status do serviço (retConsStatServ):

CampoTipoDescrição
status_codeStringCódigo de status (cStat)
status_messageStringMensagem descritiva (xMotivo)
average_timeOption<String>Tempo médio de processamento (tMed)

CancellationResponse — resposta de evento de cancelamento (retEvento):

CampoTipoDescrição
status_codeStringCódigo de status (cStat)
status_messageStringMensagem descritiva (xMotivo)
protocol_numberOption<String>Número do protocolo (nProt)

Remoção Automática do Envelope SOAP

Os parsers tratam automaticamente respostas encapsuladas em SOAP:

<!-- Resposta real da SEFAZ (com envelope SOAP e prefixos) -->
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <nfe:retConsStatServ xmlns:nfe="http://www.portalfiscal.inf.br/nfe">
      <nfe:cStat>107</nfe:cStat>
      <nfe:xMotivo>Servico em Operacao</nfe:xMotivo>
    </nfe:retConsStatServ>
  </soap:Body>
</soap:Envelope>

O parser remove os prefixos soap:, nfe: e nfeResultMsg: automaticamente, extraindo os valores das tags por nome local.

SefazClient — Métodos de Conveniência

O SefazClient combina todas as etapas (build, SOAP, envio, parse) em métodos de conveniência tipados:

use fiscal_sefaz::client::SefazClient;
use fiscal_core::types::SefazEnvironment;

let pfx = std::fs::read("certificado.pfx")?;
let client = SefazClient::new(&pfx, "senha")?;
let env = SefazEnvironment::Homologation;

// Verificar status
let status = client.status("SP", env).await?;

// Autorizar NF-e
let auth = client.authorize("SP", env, &signed_xml, "123").await?;

// Consultar por chave de acesso
let consulta = client.consult("SP", env, &access_key).await?;

// Consultar recibo (autorização assíncrona)
let recibo = client.consult_receipt("SP", env, "351000000123456").await?;

// Cancelar NF-e
let cancel = client.cancel("SP", env, &access_key, &protocol, "Justificativa", &cnpj).await?;

// Carta de Correção
let cce = client.cce("SP", env, &access_key, "Texto da correção", 1, &cnpj).await?;

// Inutilizar numeração (requer XML pré-assinado)
let raw = client.inutilize("SP", env, &signed_inut_xml).await?;

O método send() de baixo nível está disponível como escape hatch para serviços que ainda não possuem método de conveniência tipado (ex: DistribuicaoDFe, ConsultaCadastro).

Códigos de Status Comuns

cStatSignificado
100Autorizado o uso da NF-e
104Lote processado
105Lote em processamento
107Serviço em Operação
135Evento registrado e vinculado à NF-e
204Duplicidade de NF-e
217NF-e não encontrada
539Duplicidade de evento

Tratamento de Erros

Todos os métodos retornam Result<T, FiscalError>. Os erros possíveis são:

VarianteQuando ocorre
FiscalError::InvalidStateCodeUF inválida
FiscalError::CertificateFalha ao carregar PFX ou senha incorreta
FiscalError::NetworkFalha de conexão, timeout, TLS ou HTTP não-2xx
FiscalError::XmlParsingResposta malformada (sem <cStat>)
FiscalError::XmlGenerationServiço desconhecido ou <Signature> não encontrado
FiscalError::MissingRequiredFieldCampo obrigatório ausente na requisição

On this page