El ciclo
Compatibilidad hacia adelante: pueden aparecer estados nuevos del lado Xenda (por
ejemplo, etapas de logística). Tratá cualquier estado que no reconozcas como
informativo — nunca como error.
Reglas
- Aceptación implícita: mandar
listo,asignadooentregadosobre un pedidopendientelo acepta y lo mueve en un solo evento — no hace falta elaceptadoprevio. Queda auditado en el historial como aceptación implícita. - Transiciones válidas:
aceptado/rechazadosolo desdependiente;listodesdeen_preparacion;asignadodesdeen_preparacionolisto;entregadodesde cualquier estado en curso;canceladodesde cualquier estado previo al cierre. Una transición inválida devuelve400con el estado actual en el mensaje (invalid_transition: ... (current: entregado)) — útil si tu panel quedó desactualizado respecto del pedido. - Idempotencia: cada cambio de estado lleva
event_idúnico. Reintentar con el mismoevent_iddevuelveduplicate: truecon el estado vigente, sin re-aplicar. Un evento rechazado (por ejemplo, sinmotivo) no consume suevent_id: podés corregir el payload y reintentar con el mismo id, y esta vez se aplica. occurred_at: cuándo ocurrió la acción en tu sistema (el cajero aceptó a las 20:15 aunque el request salga 20:16).
Cómo distinguir los errores. Todos vienen con un
message legible; esto es lo que
significa cada código:400— el pedido o el payload no permiten esa acción: transición inválida (invalid_transition: ... (current: entregado)), falta un campo, o elmotivoes obligatorio. No reintentar igual: corregí y volvé a mandar (podés reusar el mismoevent_id).403con el mensaje empezando enrate_limited:— superaste el límite de requests por minuto de tu key. El mensaje incluye en cuántos segundos reintentar. Es temporal: reintentá, no es un problema de credenciales.403conInvalid API key— la key es incorrecta, fue revocada, o estás pegándole a un endpoint que no corresponde a su alcance.404— el pedido no existe o no pertenece a tu sucursal.
403 como “credenciales inválidas”, separá el caso del
rate limit por el prefijo del mensaje.Cancelaciones que no salen de tu POS
Un pedido puede cerrarse sin que vos lo pidas: el cliente lo cancela desde WhatsApp mientras estápendiente, o expira por el timer (más abajo). No hay push hacia tu
sistema, así que si tu flujo depende de enterarte, hay dos caminos: poll periódico de
GET /v1/orders?status=cancelado además del de pendiente, o tratar el 400 de
invalid_transition como señal de que el pedido ya se cerró y refrescar su estado.
El motivo le llega al cliente final
Cuando tu POS rechaza o cancela, el texto del motivo es el insumo con el que el
bot le explica al cliente por WhatsApp qué pasó. Escribilo pensando en esa persona:
Pedidos que expiran
En producción, un pedidopendiente que el local no acepta en un plazo configurable
(por defecto 15 minutos) se cancela automáticamente y el cliente recibe aviso —
nadie se queda esperando un helado que ningún humano vio. Para tu POS eso significa:
- Un pedido puede desaparecer de
?status=pendienteentre un poll y el siguiente. Podés consultarlo con?status=canceladosi necesitás el detalle. - Aceptar rápido es parte de la experiencia: mientras antes llegue tu
aceptado, antes recibe el cliente su confirmación.
En el sandbox la expiración está desactivada, para que puedas probar con calma.

