Skip to main content

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, asignado o entregado sobre un pedido pendiente lo acepta y lo mueve en un solo evento — no hace falta el aceptado previo. Queda auditado en el historial como aceptación implícita.
  • Transiciones válidas: aceptado/rechazado solo desde pendiente; listo desde en_preparacion; asignado desde en_preparacion o listo; entregado desde cualquier estado en curso; cancelado desde cualquier estado previo al cierre. Una transición inválida devuelve 400 con 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 mismo event_id devuelve duplicate: true con el estado vigente, sin re-aplicar. Un evento rechazado (por ejemplo, sin motivo) no consume su event_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 el motivo es obligatorio. No reintentar igual: corregí y volvé a mandar (podés reusar el mismo event_id).
  • 403 con el mensaje empezando en rate_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.
  • 403 con Invalid 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.
Si tu cliente HTTP trata todo 403 como “credenciales inválidas”, separá el caso del rate limit por el prefijo del mensaje.

Cierres que no salen de tu POS

Los estados los mueve tu POS, pero un pedido puede cerrarse sin que vos lo pidas:
  • El cliente lo cancela desde WhatsApp mientras está pendiente.
  • El local lo cierra desde la plataforma Xenda: puede marcarlo entregado o cancelarlo. Es lo único que el local puede hacer ahí con una sucursal conectada a un POS; aceptar, rechazar y los pasos intermedios son siempre de tu sistema.
  • Un tiempo automático del local lo cierra, si el local lo activó (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 (y entregado) 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 mensaje trae el estado actual: invalid_transition: ... (current: entregado).

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:

Tiempos automáticos del local

Cada local puede activar dos tiempos automáticos desde su configuración en Xenda. Vienen apagados: una sucursal nueva no cancela ni cierra nada por su cuenta. Si el local los activa, para tu POS significa:
  • Un pedido puede desaparecer de ?status=pendiente entre un poll y el siguiente. Podés consultarlo con ?status=cancelado si necesitás el detalle.
  • Un evento que llegue después del cierre (por ejemplo asignado sobre un pedido que ya se cerró solo) recibe 400 con invalid_transition.
  • Aceptar rápido es parte de la experiencia: mientras antes llegue tu aceptado, antes recibe el cliente su confirmación.
En el sandbox los dos tiempos están apagados, para que puedas probar con calma. En una sucursal real, si tu flujo no emite entregado, conviene acordar con el local y con Xenda cómo se cierran los pedidos antes de salir a producción.