order.completed dispara cuando una orden se inyecta exitosamente y está pagada. Lleva el snapshot V4 de la orden como trigger.data — todos los campos que tu flow necesita para actuar sobre la orden sin volver a llamar a Fire.
Condición de disparo
Fire emiteorder.completed exactamente una vez por orden, la primera vez que ambos son verdaderos en momento de inyección:
order.status === "COMPLETED"order.paymentStatus === "SUCCEEDED"
PENDING de pago, o que fallan el pago, nunca producen order.completed. Las cancelaciones después de completar producen un evento separado order.cancelled — no retraen order.completed.
| Cobertura | Global (todos los países, todos los canales) |
| Llave de idempotencia | event.id (= flow_executions.id) |
| Dispara más de una vez | No, salvo en reintentos — usa event.id para deduplicar |
| Orden | No garantizado entre órdenes — ordena por data.createdAt si necesitas orden |
| Reintentos | Hasta 5 intentos con backoff exponencial |
Qué hay en trigger.data
trigger.data es el snapshot V4 de la orden — el mismo objeto que se persiste en flow_queue.trigger_data y se expone a los templates de tu flow.
Las claves top-level, en orden:
| Clave | Tipo | Siempre presente |
|---|---|---|
orderId | string (UUID) | sí |
orderCode | string | null | sí |
businessDayDate | string (YYYY-MM-DD) | sí |
externalOrderId | string | sí |
redeemPoints | boolean | sí |
accumulatePoints | boolean | sí |
discount | boolean | sí |
createdAt | string | null (ISO 8601 UTC) | sí |
orderComment | string (puede ser "") | sí |
paymentStatus | string (siempre "SUCCEEDED") | sí |
status | string (siempre "COMPLETED") | sí |
marketing | object | null | sí |
store | object | sí |
device | object | sí |
channel | object | sí |
operator | object | sí |
client | object | null | sí |
payments | object | sí |
kds | object | sí |
metadata | object (a menudo {}) | sí |
orderLines | object[] | sí |
fulfillment | object | sí |
Ejemplo — payload real de producción (BR, sanitizado)
El ejemplo abajo viene de una fila real deflow_queue.trigger_data (tenant sandbox brasileño, canal KIOSK, servicio dine-in). Los campos PII se reemplazan por placeholders; el resto de los campos y formas son verbatim.
Los valores monetarios son strings expresados como unidades menores enteras × 10000 (p. ej.
"229000" = 22.9000 BRL). Esto evita drift de punto flotante a través de múltiples integraciones. Parsea con una librería decimal, nunca con parseFloat. La excepción es paymentMethods[].totalBill, que el origen a veces envía como número JSON — maneja ambos.Referencia de campos
Identificadores top-level
UUID interno de la orden en Fire. Estable a través de entregas; úsalo junto con
event.id para trazabilidad.Código corto legible mostrado en recibos y pantallas KDS (p. ej.
95K, OC-br-001). null cuando el canal no asigna uno.Día de negocio al que pertenece esta orden, en
YYYY-MM-DD. Calculado en hora local de la tienda, así que una orden hecha a las 01:00 puede pertenecer al día de negocio anterior según el corte de fin de día.El ID de orden tal como lo provee el canal/agregador en la inyección. Úsalo para reconciliar con sistemas upstream (POS, dashboards de agregador).
Timestamp ISO 8601 UTC de cuándo se hizo la orden originalmente. Distinto de
event.createdAt, que es cuándo arrancó la ejecución del flow.Siempre
"COMPLETED" para este evento.Siempre
"SUCCEEDED" para este evento.true si se canjearon puntos de fidelidad en esta orden.true si el cliente acumuló puntos de fidelidad.true si se aplicó algún descuento.Nota free-text del cliente para toda la orden. Empty string cuando no se setea.
data.store
Snapshot de la tienda en el momento que se completó la orden.
data.client
Cliente que hizo la orden.
null para órdenes de canal totalmente anónimas. Para órdenes BR de “consumidor final”, client se popula con valores placeholder (govIdType: "FINAL_CONSUMER", govIdNumber: "00000000000").data.payments
Desglose de dinero.
data.fulfillment
Cómo se entrega la orden.
data.kds
Contexto del kitchen display.
data.device y data.operator
{ uid, name, platform, metadata.ip } — dispositivo de origen. Los campos pueden ser null para canales no físicos.{ uid, name, session.uid } — staff/cajero que procesó la orden. Todos los campos null para canales self-service (kiosko, web).data.orderLines
Productos pedidos. Totalmente camelCase (transformado por el builder V4).
data.marketing, data.metadata, data.channel
Loyalty + cupones.
null en la mayoría de países hoy; reservado para uso futuro.Bag free-form para extras a nivel de orden. A menudo
{}.{ uid, code, metadata }. Ejemplos de code: KIOSK, APP, IFOOD, RAPPI.Datos fiscales
La data fiscal se incluye solo cuando la tienda tiene emisión fiscal habilitada (
store.storeFiscalConfig.enabled === true). Para países sin fiscal o tiendas sin configuración, las tres ubicaciones de abajo están ausentes o en null.order.completed lleva información fiscal en tres ubicaciones distintas. Cada una sirve un propósito distinto:
1. data.store.storeFiscalConfig — identidad del emisor y config del proveedor
Identifica la entidad legal que emite el documento y cómo autenticar con el proveedor fiscal. Las credenciales NO están aquí intencionalmente — el nodo fiscal las obtiene por proveedor/account.
2. data.payments.metadata.fiscal — agregados fiscales a nivel de orden
Totales agregados estilo SEFAZ, listos para enviar al proveedor fiscal (tu proveedor fiscal en Brasil). Los valores son strings × 10000.
3. data.orderLines[n].metadata.fiscal — clasificación fiscal por línea
Códigos fiscales por producto. Usados por el proveedor fiscal para clasificar cada línea en el documento.
taxes[n].metadata (en payments.totals[].taxes[], orderLines[].price.totalPrice[].taxes[] y orderLines[].lineTotals[].taxes[]) con códigos como cst, cBenef, cClassTrib, reducao, rateNominal, rateEffective.
Variaciones por país
El ejemplo de arriba es de una tienda brasileña con emisión fiscal habilitada — el caso más complejo. La forma del V4 es idéntica para todos los países; lo que cambia es cuánta data fiscal está populada. Hoy solo Brasil lleva los agregados por impuesto / por línea (payments.metadata.fiscal, orderLines[n].metadata.fiscal, lineTotals[n].taxes[]). Otros países tienen esos bloques presentes pero null / vacíos.
- Brasil (BR)
- Argentina (AR)
- Chile (CL)
- Colombia (CO)
- Ecuador (EC)
- Venezuela (VE)
Las tiendas brasileñas con
storeFiscalConfig.enabled === true llevan el payload fiscal completo — ver la sección Datos fiscales arriba. Marcadores de país:store.locationInfo.country.code: "BR"·name: "Brasil"·timezone: "America/Sao_Paulo"store.locationInfo.currencyCode: "BRL"store.storeFiscalConfig.govIdType: "CNPJ"(14 dígitos)store.storeFiscalConfig.secondaryGovIdType: "INSCRICAO_ESTADUAL"payments.totals[].currency_code: "BRL",paymentMethods[].currencyCode: "BRL",orderLines[].selectedCurrency: "BRL"- Populados:
payments.metadata.fiscal(vBC / vNF / vICMS / vPIS / vCOFINS / vTotTrib …),orderLines[].metadata.fiscal(ncm / cfop / csosn),lineTotals[].taxes[](ICMS, PIS, COFINS, IBS_*)
Tabla de referencia rápida
| País | country.code | Moneda efectiva | govIdType (formato) | Agregados fiscales |
|---|---|---|---|---|
| Brasil | BR | BRL | CNPJ (14 dígitos) | Sí — agregados SEFAZ completos |
| Argentina | AR | ARS | CUIT (XX-XXXXXXXX-X) | No — null / vacío |
| Chile | CL | CLP | RUT (XXXXXXXX-X) | No |
| Colombia | CO | COP | NIT (XXXXXXXXX-X) | No |
| Ecuador | EC | USD (moneda oficial de Ecuador) | RUC (13 dígitos) | No |
| Venezuela | VE | VES | RIF (J-XXXXXXXX-X) | No |
| Otros países | varía | varía | varía | No |
A medida que más países tengan un pipeline fiscal dedicado, sus eventos fiscales llegarán como
fiscal.*.{cc} (p. ej. fiscal.authorized.co, fiscal.authorized.ec). Hasta entonces, solo order.completed y order.cancelled disparan para tiendas no-BR — los bloques fiscales se quedan en null / vacíos.Handler de ejemplo
Errores comunes
- Decimales como strings × 10000.
payments.totals[0].total === "229000"significa 22.9 BRL. Usa una librería decimal; nunca conparseFloat. - El casing es mixto en
payments.totals[]y partes depaymentMethods[]. Lee tantocurrencyCodecomocurrency_codedefensivamente. El builder V4 transforma la mayor parte del snapshot pero pasa los objetos de payment sin cambios. fulfillment.deliverypuede estar presente incluso para servicios non-delivery con ceros placeholder. Ramifica siempre porfulfillment.service.code.clientpuede ser un placeholder “FINAL_CONSUMER” populado en BR — no esnull. TratagovIdType === "FINAL_CONSUMER"como anónimo para analítica.event.ides el ID de ejecución del flow, no el ID de la orden. Usaevent.idpara idempotencia (cambia por entrega), yorderIdcomo llave de negocio.- Routing multi-tenant. Usa
store.account.uid,store.vendor.uidystore.codepara enrutar al tenant correcto en tu sistema, aunque Fire ya da scope al flow de su lado.
Eventos relacionados
order.cancelled
Dispara cuando esta orden se cancela después.
order.invoiced
Solo Brasil — dispara cuando SEFAZ autoriza el documento fiscal de la orden.

