Skip to main content
Você está vendo o contrato atual (v2). Adiciona o motivo estruturado ao bloco cancellationcancellationType (código estável), cancellationGroup (categoria) e cancellationNote (texto livre), sempre presentes (null quando vazio) — sobre o snapshot v1.
order.reversed dispara quando a SEFAZ confirma o cancelamento de um documento fiscal (NFC-e ou NF-e) que tinha sido previamente autorizado. É a contraparte SEFAZ-confirmada de order.cancelled: o pedido é cancelado primeiro dentro do Fire (disparando order.cancelled), o Fire então pede o cancelamento na SEFAZ via seu provedor fiscal, e order.reversed dispara apenas quando a SEFAZ carimba o protocolo de cancelamento.

Condição de disparo

O Fire emite order.reversed uma vez por cancelamento fiscal, na primeira vez em que tudo o seguinte é verdade:
  • O pedido está em uma loja com faturamento fiscal habilitado (storeFiscalConfig.enabled === true)
  • Um documento fiscal tinha sido previamente autorizado (ou seja, order.invoiced foi emitido antes)
  • Uma solicitação de cancelamento foi enviada ao seu provedor fiscal
  • O seu provedor fiscal reporta que a autoridade fiscal confirmou o cancelamento

O que tem em trigger.data

Mesmo snapshot V4 que order.cancelled — incluindo o mesmo bloco cancellation de auditoria — com um sub-objeto extra sefazCancellation dentro de cancellation.metadata.fiscal. Essa é a única diferença estrutural. status é "CANCELLED". O pedido é o mesmo referenciado pelo evento order.cancelled anterior do mesmo orderId.

Exemplo — payload real de produção (BR, sanitizado)

Referência de data.cancellation.metadata.fiscal.sefazCancellation

Este é o único bloco que é único de order.reversed. Cada outro campo é compartilhado com order.cancelled — veja essa página para os campos de auditoria de cancelamento.
object
Confirmação SEFAZ do cancelamento. Presente apenas após a SEFAZ ter carimbado o protocolo de cancelamento.

Lifecycle

Para um pedido brasileiro fiscal-enabled, espere os quatro eventos acima. Para pedidos brasileiros sem autorização fiscal (porque o pedido foi cancelado antes da emissão fiscal, ou o fiscal estava desabilitado), apenas order.cancelled dispara — não order.reversed.

Handler de exemplo

Erros comuns

  • Não processe order.reversed sem order.cancelled primeiro. Eles disparam em ordem em fluxo normal, mas entrega fora de ordem é possível. Se você receber order.reversed para um orderId que não tem como cancelado registrado, logue e crie o registro a partir do bloco cancellation deste evento — não jogue o evento fora.
  • sefazCancellation.date e cStat podem ser null em sandbox. Não faça com que a production-readiness dependa de eles estarem presentes em ambientes dev.
  • A URL do XML de cancelamento é distinta do XML do documento original. Garanta que sua lógica de arquivamento salve ambos — você precisará deles para auditoria.
  • Mesmo cancellation.cancellationId que order.cancelled. Ambos os eventos para o mesmo cancelamento compartilham o cancellation ID — útil como chave de join ao correlacionar os dois eventos no seu sistema.
  • Não há evento para cancelamento SEFAZ falho. Se a SEFAZ rejeita a solicitação de cancelamento, nenhum evento dispara. Monitore o log de execuções do dashboard para esses casos.

Eventos relacionados

order.cancelled

Dispara antes deste evento — o cancelamento em si.

order.invoiced

O evento anterior que estabeleceu o documento fiscal sendo cancelado aqui.

data.fiscalRepresentation

Em order.reversed este bloco é especialmente relevante: são os números do comprovante que está sendo anulado. A anulação não os altera — o que muda é lastKnown.fiscal.status, que passa a cancelled.
A numeração fiscal que o ponto de venda obteve antes de injetar o pedido: cobra, pede os identificadores, imprime o comprovante e só então injeta. Por isso viaja no pedido e não em um evento fiscal separado — quando o pedido nasce, isso já aconteceu.
A presença deste bloco NÃO significa que o comprovante esteja autorizado. São os números impressos no caixa; o veredito do órgão está em lastKnown.fiscal.status. Um ticket que diga “autorizado” só porque o bloco está presente declara algo que pode não ter acontecido.
A chave viaja sempre. Chega em null quando não se tentou numerar — agregadores, países sem representação fiscal, ou comércios com a numeração desativada — e traz o bloco quando houve tentativa. Trazer o bloco significa que se tentou numerar, não que foi numerado: numberingStatus diz como a tentativa terminou, e failure por quê quando não terminou bem. Ramifique pelo valor, não pela presença da chave:
O veredicto do órgão não o altera. O que o cliente levou impresso não muda porque o órgão depois autorize ou rejeite — para isso existe lastKnown.fiscal, que é o que de fato se move. O que o substitui é um documento novo. O bloco carrega o documento fiscal vigente do pedido. Enquanto houve apenas um, era sempre a nota de venda; quando um cancelamento produz uma nota de crédito, é ela que fica no topo — documentType diz qual é — e a nota de venda desce para history, inteira e com seus próprios identificadores do órgão. Não se perde: se move. compensates aponta para ela pelo número, então a relação fica explícita.

Quando a numeração falha

Uma venda pode ser cobrada e ficar sem comprovante fiscal. Esse caso também viaja, e precisa ser tratado: os identificadores vêm null e o motivo em failure.
Ramifique por failure.scope:
  • TECHNICAL — imprima “em trâmite” e siga. Pode se resolver sozinho.
  • FUNCTIONAL — há um dado errado e repetir não resolve. Precisa correção. O que muda é lastKnown.fiscal.
lastKnown.fiscal.sourceEvent agora informa a procedência real. Antes era deduzida do status, e um processing semeado na injeção era reportado como fiscal.callback sem que nenhum callback tivesse ocorrido. Esse caso agora diz order.injected. Se você ramifica por este campo, contemple o valor novo.