Webhook de nota fiscal: como o seu sistema fica sabendo do desfecho
Um webhook de nota fiscal é o aviso que o emissor manda ao seu sistema quando uma nota muda de situação: autorizada, recusada, cancelada ou com um cancelamento que não valeu. Esta página mostra o formato do aviso, como conferir que ele veio do TexFiscal e o que acontece quando o seu servidor está fora do ar.
Por que a nota precisa de um aviso, e não só de uma resposta:
Emitir NFS-e não é uma operação de um passo só. O seu sistema pede a emissão, a prefeitura recebe, e em muitos municípios a resposta definitiva não volta na mesma chamada. A nota fica em processamento por segundos, minutos ou, nos piores dias da prefeitura, horas. Se o seu sistema só olha a resposta do pedido, ele precisa voltar depois para perguntar, e alguém precisa lembrar de fazer isso para cada venda.
O webhook inverte a direção. Em vez de o seu sistema perguntar, o TexFiscal avisa assim que a nota muda de desfecho, com uma chamada HTTP para um endereço que você cadastra. O aviso traz a mesma representação da nota que a consulta devolve, então o código que trata a consulta trata também o aviso.
O webhook não emite nada. Ele só conta o que aconteceu com uma emissão que o seu sistema pediu. A nota nasce quando o seu sistema chama a rota de emissão, e em nenhum outro momento: nenhum aviso, reenvio ou rotina agendada cria nota por conta própria.
Quais eventos chegam, e o que cada um pede de você:
- nfse_autorizada: a prefeitura autorizou. A partir daqui existem número, PDF e XML, e o seu sistema pode marcar a venda como faturada.
- nfse_erro: a prefeitura recusou. Nada foi emitido. O corpo traz os erros e a correção sugerida, e a venda continua sem nota até alguém corrigir e pedir de novo.
- nfse_cancelada: o cancelamento que você pediu foi confirmado pela prefeitura.
- nfse_cancelamento_nao_efetivado: o mais importante de todos. Você pediu o cancelamento, mas a prefeitura ainda tem a nota como autorizada. Ela continua valendo e tributável, e alguém precisa decidir se repete o pedido.
- teste: o evento que o botão do painel dispara, para você provar o receptor antes da primeira nota de verdade.
As notas de mercadoria (NF-e e NFC-e) avisam pelo mesmo canal, com os eventos equivalentes, incluindo a denegação de uso pela SEFAZ.
Repare na diferença de natureza. Autorizada e cancelada confirmam o que você já esperava. Erro, denegada e cancelamento não efetivado dizem que a realidade é diferente do que o seu sistema acredita, e por isso são os que nunca podem se perder.
Como conferir que o aviso veio do TexFiscal:
Todo aviso chega com dois cabeçalhos de autenticidade. O primeiro, X-TexFiscal-Assinatura, é o HMAC-SHA256 do corpo cru da requisição, calculado com o segredo do seu webhook. O segundo, X-Webhook-Token, é o próprio segredo, e existe para quem já tinha um receptor escrito para outro emissor de mercado continuar funcionando sem mudar nada.
Prefira a assinatura. O token prova só a origem; a assinatura prova a origem e também que o corpo não foi alterado no caminho. Calcule o HMAC sobre os bytes exatamente como chegaram, antes de interpretar o JSON, e compare com uma função de tempo constante, nunca com igualdade simples.
O segredo aparece uma vez só, no momento em que o webhook é cadastrado ou trocado. Guarde-o no mesmo lugar onde o seu sistema guarda as outras credenciais, fora do código.
<?php
$corpo = file_get_contents('php://input');
$esperada = hash_hmac('sha256', $corpo, getenv('TEXFISCAL_WEBHOOK_SEGREDO'));
$recebida = $_SERVER['HTTP_X_TEXFISCAL_ASSINATURA'] ?? '';
if (!hash_equals($esperada, $recebida)) {
http_response_code(401);
exit;
}
http_response_code(200); // responda primeiro
$evento = json_decode($corpo, true);
// grave $evento numa fila e processe depoisQuando o seu servidor está fora, o aviso espera:
A primeira tentativa acontece no mesmo instante em que a nota muda, com tempo limite de 5 segundos. Se o seu sistema não responder com sucesso, a entrega vai para a rotina agendada, que tenta de novo com espera crescente: 1 minuto, 5, 15, 60, e depois a cada 6 horas. São até 16 tentativas, o que cobre cerca de três dias de indisponibilidade.
Uma entrega aceita com resposta 2xx nunca é repetida pela rotina. Depois da última tentativa sem sucesso, a entrega fica marcada como desistida, e o painel mostra cada tentativa com o corpo enviado e a resposta recebida. Corrigido o problema do seu lado, o botão de reenviar manda de novo na hora, e o histórico continua contando, porque reenvio manual não apaga o que já aconteceu.
E se não houver webhook cadastrado? A escolha é válida, e nesse caso o seu sistema consulta a nota pela referência. Mesmo assim, os eventos que pedem ação humana (erro, denegação e cancelamento não efetivado) não ficam mudos: eles vão por e-mail ao contato do emissor, uma vez por nota e evento.
As três regras do receptor que evitam prejuízo:
- Responda rápido e processe depois. Grave o aviso numa fila e devolva 2xx. Trabalho pesado dentro da requisição estoura o tempo limite, e um aviso que você recebeu vira uma nova tentativa.
- Descarte o que chegar fora de ordem. Uma entrega que falhou e foi reagendada pode chegar depois de um evento mais novo da mesma nota: uma autorizada atrasada chegando depois da cancelada, por exemplo. O corpo traz ocorrido_em. Guarde o último aplicado por referência e ignore o que for mais antigo.
- Trate a entrega repetida. Se a sua resposta se perder na rede, o mesmo aviso chega duas vezes. O campo evento_id é único e estável: use-o como chave para não aplicar duas vezes o mesmo fato.
Nenhuma das três é exagero. São os três defeitos mais comuns em receptor de nota fiscal, e o segundo marca como autorizada uma nota que já foi cancelada, que é exatamente o tipo de erro que só aparece na apuração do mês.
Como cadastrar, e o que o cadastro recusa:
O webhook é um por emissor e por ambiente: um endereço para homologação e outro para produção, cada um com o seu segredo. O cadastro pode ser feito no painel ou pela própria API, com o token do ambiente.
O endereço precisa ser https, não pode ter usuário embutido e não pode apontar para dentro de uma rede privada. O nome do host é resolvido no cadastro, e um nome público que aponte para endereço interno é recusado, porque o segredo vai em todo aviso e mandá-lo para o lugar errado é entregar a credencial.
Trocar um webhook ativo é um ato deliberado: pela API, o pedido precisa dizer "substituir": true, e a troca gera um segredo novo. O seu receptor precisa adotar o segredo novo no mesmo momento, e é por isso que a troca não acontece por engano.
curl -u "SEU_TOKEN:" -X POST https://homologacao-nfse.texfiscal.com.br/v2/hooks \
-H "Content-Type: application/json" \
-d '{"url": "https://seu-sistema.com.br/texfiscal/aviso"}'
O segredo volta UMA vez nesta resposta. Guarde antes de fechar o terminal.Perguntas frequentes:
O webhook emite a nota automaticamente?
Quantas vezes o TexFiscal tenta entregar um aviso?
Como sei que o aviso é legítimo e não foi forjado?
Preciso cadastrar um webhook para usar a API?
Dá para testar o receptor antes da primeira nota?
O que fazer quando chega o aviso de cancelamento não efetivado?
Página atualizada em: 19/10/2026