- v2 · current
- v1 · deprecated
- v0 · deprecated
You’re viewing the current (v2) contract. It adds a structured cancellation motive to the
cancellation block — cancellationType (stable code), cancellationGroup (category) and cancellationNote (free text), always present (null when empty) — on top of the v1 order snapshot.order.reversed fires when SEFAZ confirms the cancellation of a fiscal document (NFC-e or NF-e) that had been previously authorized. It is the SEFAZ-confirmed counterpart to order.cancelled: the order is cancelled first inside Fire (firing order.cancelled), Fire then requests cancellation at SEFAZ via your fiscal provider, and order.reversed fires only when SEFAZ stamps the cancellation protocol.
Trigger condition
Fire emitsorder.reversed once per fiscal cancellation, the first time all of these are true:
- The order is in a store with fiscal billing enabled (
storeFiscalConfig.enabled === true) - A fiscal document had been previously authorized (i.e.
order.invoicedwas emitted earlier) - A cancellation request was submitted to your fiscal provider
- your fiscal provider reports the fiscal authority’s confirmation of the cancellation
What’s in trigger.data
Same V4 order snapshot as order.cancelled — including the same cancellation audit block — with an extra sefazCancellation sub-object inside cancellation.metadata.fiscal. That’s the only structural difference.
status is "CANCELLED". The order is the same one referenced by the earlier order.cancelled event for the same orderId.
Example — real production payload (BR, sanitized)
data.cancellation.metadata.fiscal.sefazCancellation reference
This is the only block that’s unique to order.reversed. Every other field is shared with order.cancelled — see that page for the cancellation audit fields.
object
SEFAZ confirmation of the cancellation. Present only after SEFAZ has stamped the cancellation protocol.
Lifecycle
For a Brazilian fiscal-enabled order, expect the four events above. For Brazilian orders without fiscal authorization (because the order was cancelled before fiscal emission, or fiscal was disabled), onlyorder.cancelled fires — no order.reversed.
Handler example
Common pitfalls
- Don’t process
order.reversedwithoutorder.cancelledfirst. They fire in order in normal flow, but out-of-order delivery is possible. If you receiveorder.reversedfor anorderIdyou don’t have a cancellation record for, log it and create the record from this event’scancellationblock — don’t drop the event. sefazCancellation.dateandcStatmay benullin sandbox. Don’t make production-readiness depend on them being present in dev environments.- The cancellation XML URL is distinct from the original document XML. Make sure your archival logic stores both — you’ll need them for audit.
- Same
cancellation.cancellationIdasorder.cancelled. Both events for the same cancellation share the cancellation ID — useful as a join key when correlating the two events in your system. - No event for failed SEFAZ cancellation. If SEFAZ rejects the cancellation request, no event fires. Monitor the dashboard’s executions log for those cases.
Related events
order.cancelled
Fires before this event — the cancellation itself.
order.invoiced
The earlier event that established the fiscal document being cancelled here.
data.fiscalRepresentation
On
order.reversed this block matters especially: these are the numbers of the
receipt being annulled. The annulment does not change them — what changes is
lastKnown.fiscal.status, which becomes cancelled.null when numbering was not
attempted — aggregators, countries without fiscal representation, or merchants
with numbering turned off — and carries the block when it was.
Carrying the block means numbering was attempted, not that it succeeded:
numberingStatus tells you how the attempt ended, and failure why, when it did
not end well.
Branch on the value, not on the key’s presence:
lastKnown.fiscal is for, and that is what does move.
What does replace it is a new document. The block carries the order’s
current fiscal document. While there was only one, it was always the invoice;
when a cancellation produces a credit note, the note is what sits on top —
documentType says which one — and the invoice moves down into history,
whole and with its own authority identifiers. It is not lost: it moves.
compensates points at it by number, so the relationship stays explicit.
When numbering fails
A sale can be charged and end up with no fiscal receipt. That case travels too, and you must handle it: the identifiers come backnull and the reason is
in failure.
failure.scope:
TECHNICAL— print “pending” and carry on. It may resolve on its own.FUNCTIONAL— some data is wrong and retrying will not fix it. Needs correction.
lastKnown.fiscal.sourceEvent now reports real provenance. It used to be
derived from the status, so a processing seeded at injection was reported as
fiscal.callback even though no callback had occurred. That case now says
order.injected. If you branch on this field, account for the new value.
