Pular para o conteúdo principal

Webhook events + validação HMAC

A NFE.io envia HTTP POST ao endpoint configurado em webhookUrl da empresa sempre que um documento NF-e ou CT-e novo (ou evento associado) é capturado do Ambiente Nacional da SEFAZ. Este documento cataloga os eventos, o shape do payload, a política de entrega e os mecanismos de segurança.

Sumário

Política de entrega

  • Entrega: at-least-once — seu handler deve ser idempotente.
  • Method: POST com Content-Type: application/json; charset=utf-8.
  • Timeout: 30 segundos para sua resposta.
  • Retry: até 24 horas com backoff exponencial.
  • Códigos: 2xx confirma entrega; 4xx (exceto 408/429) marca falha definitiva sem retry; 408/429/5xx ou timeout disparam retry.
  • Assinatura: header x-hub-signature com HMAC-SHA1 do body bruto, formato sha1=<HEX> — ver Validação HMAC.

Após esgotar as tentativas, o documento permanece consultável via API. Reenvie manualmente com POST /v2/companies/{companyId}/inbound/productinvoices/{access_key}/processwebhook.

Eventos

Quando um documento é recebido, fazemos um POST para sua URL. O tipo de evento chega em dois lugares: o header X-Hook-Event identifica a área (NF-e ou CT-e) e o campo body.action identifica a ação específica.

X-Hook-Eventbody.actionQuando ocorre
product_invoice_inboundissued_successfully | outbound_successfullyNF-e recebida (ou emitida pela própria conta, se você optou por recebê-las)
product_invoice_inboundinput_event_raised_successfullyEvento de manifestação do destinatário (Ciência, Confirmação, Desconhecimento, Operação não Realizada)
product_invoice_inboundevent_raised_successfullyOutro evento de NF-e (cancelamento, CC-e, EPEC, eventos NT 2025.002)
product_invoice_inbound_summarymesmos valores acimaVariante resumida (sem XML completo) do mesmo evento
transportation_invoice_inboundissued_successfully | outbound_successfullyCT-e recebido (ou emitido pela própria conta)
transportation_invoice_inboundevent_raised_successfullyEvento de CT-e

Formato do Payload

O corpo é sempre embrulhado num envelope {"body": {...}}. Exemplo de NF-e recebida (X-Hook-Event: product_invoice_inbound, body.action: issued_successfully):

{
"body": {
"action": "issued_successfully",
"accountId": "5f9a1b2c3d4e5f6a7b8c9d0e",
"accessKey": "35240112345678000195550010000012341234567890",
"createdOn": "2024-03-15T14:22:10Z",
"parentAccessKey": "",
"company": {
"id": "comp_123",
"federalTaxNumber": "98765432000100"
},
"issuer": {
"federalTaxNumber": "12345678000195",
"name": "Fornecedor LTDA"
},
"buyer": {
"federalTaxNumber": "98765432000100",
"name": "Minha Empresa S.A."
},
"links": {
"xml": "https://api.nfe.io/v2/companies/comp_123/inbound/nfe/35240112345678000195550010000012341234567890/xml",
"pdf": "https://api.nfe.io/v2/companies/comp_123/inbound/nfe/35240112345678000195550010000012341234567890/pdf"
},
"blobUrl": "comp_123/2024/03/35240112345678000195550010000012341234567890.xml",
"type": "productInvoice",
"nsu": "21825",
"nsuParent": "",
"nfeNumber": "1234",
"nfeSerialNumber": "1",
"issuedOn": "2024-03-15T10:00:00Z",
"description": "Autorizado o uso da NF-e",
"totalInvoiceAmount": "1500.00",
"operationType": "Incoming",
"environmentType": 1,
"direction": "Received"
}
}

Note que totalInvoiceAmount é string, e o identificador da empresa vem em company (objeto), não em um campo solto companyId.

Para CT-e, os campos issuer (transportadora) e taker (tomador do serviço) substituem issuer/buyer. Para eventos (body.action = event_raised_successfully ou input_event_raised_successfully), o body carrega também o eventCode e o tipo de evento associado.

Fluxo end-to-end

Validação HMAC

A NFE.io assina cada POST com HMAC-SHA1 sobre o body bruto. Validar a assinatura é obrigatório — sem isso, qualquer um que descubra a URL do seu endpoint pode forjar requisições.

ItemValor
Headerx-hub-signature (lowercase)
AlgoritmoHMAC-SHA1
Encodinghex MAIÚSCULO, sem separadores
Formatosha1=<HEX> (prefixo obrigatório, 45 chars total)
Conteúdo assinadoBody bruto UTF-8, exatamente como recebido
SecretString ASCII de 32 a 64 caracteres, configurada na subscrição

Vetor de teste

Secret: SuperSecretWebhookKey12345678901
Body: {"event":"test","id":"abc123","amount":42.00}
→ Header: sha1=502BC91DE70F6802FC16CD2E599A9AF752064FE5

Se sua implementação não gera exatamente esse hash com esses inputs, ela tem um bug — corrija antes de testar contra webhook real.

Exemplo (Python/Flask)

import hmac, hashlib
from flask import request, abort

WEBHOOK_SECRET = b"<seu-segredo-32-a-64-chars>"

@app.post("/webhook/nfeio")
def receive():
sig = request.headers.get("x-hub-signature", "")
if not sig.startswith("sha1="):
abort(401)
expected = "sha1=" + hmac.new(
WEBHOOK_SECRET, request.get_data(cache=True), hashlib.sha1
).hexdigest().upper()
if not hmac.compare_digest(expected, sig):
abort(401)
# processar request.json["body"] — veja X-Hook-Event / body["action"]
return "", 200

Use comparacão timing-safe (hmac.compare_digest em Python, crypto.timingSafeEqual em Node, CryptographicOperations.FixedTimeEquals em C#) — comparação byte-a-byte vaza informação por análise de tempo.

Documentação completa

Catálogo canônico (PT/EN/ES, 13 seções, 5 implementações de referência, troubleshooting, rotação de secret): https://github.com/nfe/shared-webhook-api/blob/main/docs/webhook-signature-validation.md

Não confunda autenticação com integridade

x-hub-signature (HMAC) autentica — prova que o webhook veio da NFE.io e não foi adulterado.

Content-MD5 apenas detecta corrupção em trânsito — qualquer atacante pode calcular o MD5 do payload forjado dele. MD5 ≠ autenticação.

Idempotência

Webhooks podem chegar mais de uma vez após retry. Seu handler deve deduplicar usando (companyId, accessKey) ou (companyId, nsu) como chave única.

Boas práticas adicionais:

  • Responda rápido: retorne 2xx em até 5 segundos e processe assincronamente (fila interna).
  • Persista o payload antes de processar — não perca dados em crash do consumer.
  • Baixe XML/PDF cedo — URLs assinadas em links.xml expiram em 1 hora.
  • Monitore HTTP 5xx no seu endpoint — detecte problemas antes que o orçamento de retry esgote.

Veja também

NFE.io

A NFE.io é uma empresa de tecnologia que fornece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas. Com suas ferramentas, as empresas podem economizar tempo e reduzir erros, aumentando a eficiência e precisão do processo de emissão de notas fiscais.

Um dos principais cases de sucesso da NFE.io é a implementação da solução na empresa de transporte Rodonaves. Com a automatização da emissão e gestão de notas fiscais eletrônicas, a Rodonaves conseguiu reduzir em até 80% o tempo gasto nesse processo, o que se traduziu em uma significativa melhoria na eficiência operacional. Além disso, a empresa também conseguiu eliminar erros e atrasos na emissão de notas fiscais, o que melhorou a relação com seus clientes e aumentou a confiança dos órgãos fiscais.

Outro exemplo é a implementação da NFE.io na empresa de comércio eletrônico, a Loja Integrada. Com a automatização da emissão de notas fiscais, a Loja Integrada conseguiu aumentar a velocidade de emissão de notas em até 10 vezes, o que permitiu que a empresa atendesse a uma maior quantidade de clientes e, consequentemente, aumentar as suas vendas.

Além desses exemplos, a NFE.io também tem outros cases de sucesso com empresas de setores como indústria, construção, varejo e serviços, mostrando a versatilidade e eficácia da sua solução.

Em resumo, a NFE.io é uma empresa de tecnologia que oferece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas, ajudando as empresas a economizar tempo e reduzir erros, melhorando a eficiência e precisão do processo. Com cases de sucesso em diferentes setores, a NFE.io tem se destacado como uma empresa líder em automação fiscal.