Skip to main content
Estás viendo el contrato actual (v1.1) de order.opened. v1.1 agrega data.fiscalRepresentation: la numeración fiscal que el punto de venta obtuvo antes de inyectar la orden. Viaja siempre: en null cuando no se intentó numerar, y con contenido cuando sí —numberingStatus dice cómo terminó—. Que traiga contenido no significa que el comprobante esté autorizado. Solo aditivo — nada de lo que ya leías cambió.El bloque lleva el documento fiscal vigente de la orden: los campos que significan lo mismo en todo país arriba, los identificadores del ente dentro de countryData con el vocabulario de su país, y los documentos anteriores en history. Cuando una anulación numera, la nota de crédito pasa arriba y la factura baja al histórico — con compensates apuntando a ella.
order.opened se dispara cuando una orden se inyecta ya abierta: existe en Fire, la cocina puede arrancar, pero no hay ningún pago confirmado. Lleva el mismo snapshot V4 que order.completed, así que todo lo que podés hacer sobre una orden completada también podés hacerlo acá. Este es el evento que hace posible el pago diferido. Sin él, una orden impaga sería invisible para tus integraciones hasta que llegara el dinero.

Condición de disparo

Fire emite order.opened una vez, al inyectar, cuando:
  • order.status === "OPEN"
Esa es la única condición. A diferencia de order.completed, no hay guarda de pagopaymentStatus normalmente viene en "PENDING" y eso es lo esperado.
order.opened no se dispara para órdenes inyectadas como COMPLETED o CANCELLED. Esas órdenes nunca “se abren”: se saltean el ciclo de pago diferido por completo y producen únicamente order.completed. Emitirlo para ellas arriesgaría despachar la misma orden dos veces a la cocina.

La vida de la orden después de este evento

order.opened es el primero de hasta tres eventos de la misma orden. Conocer la secuencia importa, porque esa orden va a llegar a tu endpoint más de una vez:
Una orden cancelada antes del pago produce order.cancelled en vez de order.completed.
Si tu flujo emite un documento fiscal en order.opened, la misma orden va a pasar de nuevo por tu nodo fiscal en order.completed. Ese segundo paso es esperado e inofensivo: Fire detecta el documento existente y devuelve un resultado idempotente de “ya facturada” en vez de emitir otro. Ver Política de pago diferido más abajo.

Qué trae trigger.data

trigger.data es el snapshot V4 — exactamente la misma estructura que lleva order.completed, con dos diferencias que conviene esperar: Esa última fila es la que sorprende a los integradores. Leela con cuidado.

El medio declarado no es el medio cobrado

En order.opened nadie pagó, así que payments.paymentMethods[] lleva el medio que el POS anunció al crear la orden — muchas veces el marketplace (IFOOD, RAPPI) o un placeholder. transactionStatus viene en "PENDING" y transactionId normalmente vacío. Cuando entra el cobro, Fire sobreescribe ese arreglo con los tenders reales y emite order.completed. Misma orden, mismo campo, significado distinto:
order.opened — declarado
order.completed — realmente cobrado
Nunca trates payments.paymentMethods[] de order.opened como evidencia de cobro. Es una intención, no un hecho. Si necesitás saber qué se recaudó de verdad, esperá order.completed o llamá a Get order, que expone settlement.

Política de pago diferido

data.policy.deferredPayment es la razón de ser de este evento. Te dice si esta orden puede ser trabajada antes del pago: cocinada, facturada, despachada. La política se resuelve una sola vez, al inyectar la orden, a partir de la combinación canal × servicio × medio de pago declarado. Después se estampa de forma inmutable en la orden, y todos los eventos posteriores la repiten sin recalcularla. Dos eventos de la misma orden siempre llevan una policy idéntica.
¿Por qué inmutable? Porque la decisión tiene que quedar auditable. Si la configuración de la tienda cambia una hora después, una orden ya en vuelo debe seguir comportándose como se le indicó — y vos tenés que poder demostrar por qué. Mismo patrón que store.storeFiscalConfig.
policy está presente en todos los eventos de orden (order.opened, order.completed, order.invoiced, order.cancelled), no solo en este. Una orden con eligible: false también lleva el bloque — simplemente dice que la respuesta fue no.

Último estado conocido

data.lastKnown es una foto orientativa de lo que Fire sabía del estado de cocina y fiscal de la orden en el momento de emitir el evento.
lastKnown es una pista, nunca una fuente de verdad. Puede estar viejo, y en order.opened es habitual que venga null simplemente porque todavía no pasó nada. No condiciones una acción irreversible a este campo — si estás por emitir un documento fiscal, las devoluciones no son algo que quieras descubrir que necesitabas. Verificá el estado real, o apoyate en la idempotencia de Fire.Fire mismo sigue esta regla: su nodo fiscal relee el estado del documento desde la fuente antes de emitir, e ignora lastKnown por completo.
Valores posibles de fiscal.status: pending, processing, authorized, contingency, cancelling, cancelled, rejected, denied, error. Fire además lleva dos estados internos para órdenes sin documento todavía — esos se reportan acá como null, para no filtrar contabilidad interna dentro de tu contrato.

Todo lo demás

Los bloques restantes — store, client, channel, orderLines, fulfillment, kds, device, operator, marketing, metadata, payments.totals — son idénticos a order.completed. En vez de duplicarlos, mirá la referencia de campos de order.completed.

Errores comunes

No lo es. Nadie pagó. Contar order.opened en reportes de facturación infla los números y duplica cuando llegue order.completed de la misma orderId.
Las órdenes pre-pagas (kiosco, checkout web) se inyectan ya COMPLETED y nunca lo emiten. Si tu integración depende de que order.opened llegue primero, va a saltear esas órdenes en silencio. Suscribite a los dos.
Ver más arriba. En order.opened es lo que el POS declaró, no lo que se cobró.
La misma orderId te llega en order.opened y otra vez en order.completed. Es por diseño. Hacé tu handler idempotente por (orderId, acción), no por orderId.

Siguiente

data.fiscalRepresentation

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.