Skip to main content
Estás viendo el contrato actual (v2). Agrega el motivo estructurado al bloque cancellationcancellationType (código estable), cancellationGroup (categoría) y cancellationNote (texto libre), siempre presentes (null si vacío) — sobre el snapshot v1.
order.reversed dispara cuando SEFAZ confirma la cancelación de un documento fiscal (NFC-e o NF-e) que había sido previamente autorizado. Es la contraparte SEFAZ-confirmada de order.cancelled: la orden se cancela primero dentro de Fire (disparando order.cancelled), Fire después pide la cancelación en SEFAZ vía tu proveedor fiscal, y order.reversed dispara solo cuando SEFAZ estampa el protocolo de cancelación.

Condición de disparo

Fire emite order.reversed una vez por cancelación fiscal, la primera vez que todo lo siguiente es verdadero:
  • La orden está en una tienda con facturación fiscal habilitada (storeFiscalConfig.enabled === true)
  • Un documento fiscal había sido previamente autorizado (es decir, order.invoiced se emitió antes)
  • Se envió una solicitud de cancelación a tu proveedor fiscal
  • tu proveedor fiscal reporta que la autoridad fiscal confirmó la cancelación

Qué hay en trigger.data

Mismo snapshot V4 que order.cancelled — incluyendo el mismo bloque cancellation de auditoría — con un sub-objeto extra sefazCancellation dentro de cancellation.metadata.fiscal. Esa es la única diferencia estructural. status es "CANCELLED". La orden es la misma referenciada por el evento order.cancelled previo del mismo orderId.

Ejemplo — payload real de producción (BR, sanitizado)

Referencia de data.cancellation.metadata.fiscal.sefazCancellation

Este es el único bloque que es único de order.reversed. Cada otro campo se comparte con order.cancelled — consulta esa página para los campos de auditoría de cancelación.
object
Confirmación SEFAZ de la cancelación. Presente solo después de que SEFAZ haya estampado el protocolo de cancelación.

Lifecycle

Para una orden brasileña fiscal-enabled, espera los cuatro eventos arriba. Para órdenes brasileñas sin autorización fiscal (porque la orden se canceló antes de la emisión fiscal, o fiscal estaba deshabilitado), solo dispara order.cancelled — no order.reversed.

Handler de ejemplo

Errores comunes

  • No proceses order.reversed sin order.cancelled primero. Disparan en orden en flujo normal, pero entrega fuera de orden es posible. Si recibes order.reversed para un orderId que no tienes registrado como cancelado, loguéalo y crea el registro desde el bloque cancellation de este evento — no botes el evento.
  • sefazCancellation.date y cStat pueden ser null en sandbox. No hagas que la production-readiness dependa de que estén presentes en entornos dev.
  • El XML URL de cancelación es distinto del XML del documento original. Asegúrate que tu lógica de archivado guarde ambos — los necesitarás para auditoría.
  • Mismo cancellation.cancellationId que order.cancelled. Ambos eventos para la misma cancelación comparten el cancellation ID — útil como llave de join cuando correlacionas los dos eventos en tu sistema.
  • No hay evento para cancelación SEFAZ fallida. Si SEFAZ rechaza la solicitud de cancelación, no dispara evento. Monitorea el log de ejecuciones del dashboard para esos casos.

Eventos relacionados

order.cancelled

Dispara antes de este evento — la cancelación misma.

order.invoiced

El evento previo que estableció el documento fiscal que se cancela acá.

data.fiscalRepresentation

En order.reversed este bloque es especialmente relevante: son los números del comprobante que se está anulando. La anulación no los cambia — lo que cambia es lastKnown.fiscal.status, que pasa a cancelled.
La numeración fiscal que el punto de venta obtuvo antes de inyectar la orden: cobra, pide los identificadores, imprime el comprobante y recién después inyecta. Por eso viaja en la orden y no en un evento fiscal aparte — cuando la orden nace, esto ya ocurrió.
Que este bloque exista NO significa que el comprobante esté autorizado. Son los números que se imprimieron en la caja; el veredicto del ente lo da lastKnown.fiscal.status. Un ticket que diga “autorizado” solo porque el bloque está presente declara algo que puede no haber pasado.
La clave viaja siempre. Llega en null cuando no se intentó numerar —agregadores, países sin representación fiscal, o comercios con la numeración desactivada— y con el bloque cuando sí se intentó. Que traiga bloque significa que se intentó numerar, no que se numeró: numberingStatus dice cómo terminó el intento, y failure por qué cuando no terminó bien. Ramificá por valor, no por presencia de la clave:
El veredicto del ente no lo altera. Lo que el cliente se llevó impreso no cambia porque el organismo después autorice o rechace; para eso está lastKnown.fiscal, que es lo que sí se mueve. Lo que sí lo reemplaza es un documento nuevo. El bloque lleva el documento fiscal vigente de la orden. Mientras solo hubo uno, era siempre la factura; cuando una anulación produce una nota de crédito, arriba queda la nota — documentType dice cuál es— y la factura baja a history, entera y con sus propios identificadores del ente. No se pierde: se mueve. compensates apunta a ella por su número, así que la relación entre los dos queda explícita.

Cuando la numeración falla

Una venta puede cobrarse y quedarse sin comprobante fiscal. Ese caso también viaja, y hay que contemplarlo: los identificadores vienen en null y el motivo en failure.
Ramificá por failure.scope:
  • TECHNICAL — imprimí “en trámite” y seguí. Puede resolverse solo.
  • FUNCTIONAL — hay un dato mal y reintentar no lo arregla. Requiere corrección.
lastKnown.fiscal.sourceEvent ahora informa la procedencia real. Antes se deducía del estado, y un processing sembrado al inyectar se reportaba como fiscal.callback sin que ningún callback hubiera ocurrido. Ahora ese caso dice order.injected. Si ramificás por este campo, contemplá el valor nuevo.