Estado de orden de agregador
API
Estado de orden de agregador
Endpoint entrante al que tu agregador de delivery (Rappi / Uber / Didi / iFood …) hace POST a medida que mueve una orden por su ciclo de vida de entrega. Fire refleja el estado en la orden y registra el evento. El estado es passthrough — las etiquetas propias del agregador, guardadas tal cual.
POST
Estado de orden de agregador
Este endpoint es entrante — tu agregador de delivery (Rappi, Uber, Didi, iFood, PedidosYa, Glovo…) le hace POST cada vez que avanza la orden de su lado: se asignó un repartidor, la orden fue retirada, está en ruta, fue entregada, y así. Fire autentica la solicitud, correlaciona la orden, refleja el último estado en
Ambos son vendor-scoped: la orden correlacionada debe pertenecer a la cuenta + vendor ligados a tu API key, y su canal debe coincidir con
Se devuelve
El estado crudo se guarda tal cual; cualquier etiqueta amigable y traducida se resuelve al momento de mostrar desde el catálogo de estados del canal — el valor guardado nunca cambia.
orders.aggregator, y registra el evento en su log de eventos de agregador para observabilidad.
Este endpoint es asíncrono. Fire autentica, correlaciona la orden (guards de tenant + canal), deduplica y encola el evento — luego responde
202 Accepted con un webhookEventId (típicamente en menos de 100 ms). El espejo de la orden se actualiza un instante después en un worker en segundo plano (normalmente en ~2 segundos). Para verificar el resultado, consultá GET /v1/webhooks/events/{webhookEventId}. Los problemas corregibles por el cliente (payload inválido, orden no encontrada, tenant o canal equivocado, ids en conflicto) se rechazan síncronamente con 4xx antes del 202.El estado es passthrough. Los agregadores no comparten un vocabulario de estados, así que Fire no impone un enum:
status se guarda tal cual como el tipo de evento (courier_assigned, on_route, entregue, lo que use tu canal). El estado actual de la orden es el del occurredAt más reciente — no un orden de ciclo de vida fijo. No hay compuerta anti-regresión: un timestamp posterior gana, punto. Las etiquetas amigables y traducidas son un asunto de presentación que se resuelve desde el catálogo del canal, nunca se imponen aquí.No hay un
eventId emitido por Fire para ecoar. A diferencia del callback fiscal y los estados KDS — que ecoan un event.id que Fire emitió — un estado de agregador es un evento externo espontáneo. Fire no es la fuente de verdad acá, así que no hay chequeo de fuente de verdad sobre un eventId. En cambio, vos le decís a Fire a qué orden pertenece el estado, vía resolución de la orden abajo. La idempotencia se llavea por tu providerEventId (ver Idempotencia).Resolución de la orden
Debés decirle a Fire a qué orden pertenece este estado. Hay dos caminos, y podés enviar uno o ambos — al menos uno es requerido:| Campo | Correlaciona por | Cuándo usarlo |
|---|---|---|
orderId | Nuestro orders.id (UUID) | Guardaste el id de orden de Fire (ej. ecoado de un evento saliente o de la respuesta de inyección) |
externalOrderId | El id de orden externo (XMART/agregador), comparado contra el metadata.order_id de la orden | Solo conocés tu propia referencia de orden |
channelCode.
Autenticación
Este endpoint requiere una API key vendor-scoped con el scopewebhooks:aggregator (binding de cuenta + vendor). Fire valida que la orden correlacionada pertenezca a ese vendor. Las keys sin el scope, o sin binding de vendor, se rechazan con 403 Forbidden.
Tu API key vendor-scoped de Fire con scope
webhooks:aggregator. Generá una desde Developers → Gestión de API para la cuenta/vendor cuyas órdenes reportará esta key.Bearer <token> opcional — aceptado como alternativa legacy a x-api-key. Enviá uno u otro.Cuerpo de la solicitud
El código de agregador/canal — debe ser igual al
metadata.channel.code de la orden (channels.code, ej. RAPPI, UBER, o el id numérico de canal como 99). Si no coincide con el canal de la orden correlacionada, Fire responde 403.El estado de entrega crudo, passthrough — guardado tal cual como el tipo de evento. Se acepta cualquier string no vacío (
accepted, courier_assigned, picked_up, on_route, delivered, cancelled, o las etiquetas propias de tu canal). No se impone ningún enum.El id propio de tu agregador para esta entrega — la llave de idempotencia (junto con
channelCode). Fire mapea (channelCode, providerEventId) a un id de evento interno estable, así que reenviar el mismo par con el mismo status es un replay seguro. Usá el id de evento nativo si lo tenés; si no, un UUID.Timestamp ISO 8601 UTC de cuándo cambió el estado del lado del agregador — no cuándo se envió. Esto es lo que ordena el recorrido: el estado con el
occurredAt más reciente es el estado actual de la orden.UUID de la orden en Fire. Requerido si
externalOrderId está ausente. Ver Resolución de la orden.El id de orden externo (XMART/agregador), comparado contra el
metadata.order_id de la orden. Requerido si orderId está ausente. Ver Resolución de la orden.Bolsa libre opcional de campos extra (nombre del repartidor, url de tracking, etc.). Se guarda tal cual, sin validar.
Ejemplos
Los reportes de la misma entrega comparten unchannelCode y correlacionan a la misma orden; cada uno lleva su propio status, providerEventId y occurredAt:
courier_assigned (por orderId de Fire)
on_route (por id de orden externo)
delivered (ambos ids — deben apuntar a la misma orden)
Respuesta
En éxito el endpoint responde202 Accepted — el evento fue autenticado, correlacionado, deduplicado y encolado. Un 202 no significa que el espejo de la orden ya se actualizó; eso ocurre de forma asíncrona. Usá el endpoint de estado para confirmar.
El body trae dos ids distintos: eventId es el id interno estable de Fire para este par (channelCode, providerEventId), webhookEventId es el id de Fire para el registro encolado. Misma forma que el callback fiscal.
Siempre
true cuando la solicitud fue aceptada y encolada.true cuando este reporte de estado exacto ya se ingresó (misma orden, mismo (channelCode, providerEventId), mismo status) — se devuelve el registro existente y no se re-encola nada. false para un reporte nuevo (incluido un status distinto de la misma entrega — eso es un paso nuevo, no un duplicado).El id interno estable de Fire derivado de
(channelCode, providerEventId).El id de Fire para el registro encolado. Pasalo a
GET /v1/webhooks/events/{webhookEventId} para consultar el resultado. En un duplicado es el mismo id que se devolvió la primera vez.Estado actual en la cola —
queued → processing → processed (y retry / failed / dead / ignored).Timestamp ISO 8601 UTC de cuándo Fire recibió por primera vez este reporte. Estable entre reintentos.
Resumen legible.
Verificar el resultado
Como el procesamiento es asíncrono, el202 solo confirma que el evento fue encolado. Para ver si el espejo de la orden se actualizó, consultá el endpoint de estado con el webhookEventId que devolvió el 202:
Ciclo de vida de la cola:
queued → processing → processed (listo) · failed / dead (se rindió tras reintentos) · retry (esperando el próximo intento) · ignored (manejado, sin acción — ej. un duplicado).Intentos de procesamiento hasta ahora.
En éxito, el resultado del worker — ej.
{ "kind": "merged", "current": "delivered" }.{ "message": "…" } cuando el último intento falló; null si no.404 para ids desconocidos — o ids de otro tenant — sin filtrar existencia. Autenticá con la misma key webhooks:aggregator que usaste para el evento.
Idempotencia y el recorrido
Fire deduplica por la orden más(channelCode, providerEventId) y el status — no por un eventId emitido por Fire. Esto es lo que hace funcionar el recorrido manteniendo limpios los reintentos:
| Escenario | Resultado |
|---|---|
courier_assigned, luego on_route, luego delivered — status distinto (y providerEventId), misma orden | cada uno es un paso nuevo → 202 duplicate:false |
El mismo reporte reenviado — misma orden, mismo (channelCode, providerEventId), mismo status | 202 duplicate:true — registro existente devuelto, no reprocesado |
Ni orderId ni externalOrderId enviados | 400 |
| Orden no encontrada para este vendor | 404 |
orderId y externalOrderId correlacionan a órdenes distintas | 409 |
channelCode ≠ el canal de la orden, o key no es de este vendor | 403 |
| Auth store momentáneamente inalcanzable | 503 — transitorio, reintentá |
Un
status distinto nunca es un duplicado. Como los agregadores reportan legítimamente muchos estados para una entrega, dos reportes con el mismo (channelCode, providerEventId) pero un status distinto son dos pasos distintos — Fire guarda ambos. Mantené providerEventId único por reporte de estado para no reproducir un paso por accidente.El espejo de la orden
Una vez procesado, el último estado se refleja en el bloqueaggregator de la orden, con el recorrido completo guardado en history (ordenado por occurredAt). El status actual es la entrada con el occurredAt más reciente:
orders.aggregator
Relacionado
Inyectar orden
El endpoint de inyección que crea la orden que este estado referencia.
Estado de orden KDS
El webhook entrante hermano para el estado de cocina — mismo modelo async + cola, pero con
eventId emitido por Fire y anti-regresión.Callback fiscal
El webhook entrante fiscal — mismo envelope async + idempotencia.
Autenticación
Cómo funcionan las API keys, scopes y el binding de vendor.

