> ## Documentation Index
> Fetch the complete documentation index at: https://partner-api.xenda.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Estados del pedido

> Ciclo de vida del pedido, qué informa tu POS y qué maneja Xenda.

## El ciclo

```
pendiente ──aceptado──► en_preparacion ──► listo ──► entregado
    │                        │                ▲
    │                        └──► asignado ───┘──► entregado
    │
    ├──rechazado──► (terminal, con motivo)
    └──cancelado──► (terminal, con motivo — en cualquier punto previo a la entrega)
```

| Estado           | Quién lo pone              | Notas                                                                                                     |
| ---------------- | -------------------------- | --------------------------------------------------------------------------------------------------------- |
| `pendiente`      | Xenda                      | El bot cerró el pedido con el cliente; espera confirmación del local                                      |
| `en_preparacion` | Tu POS (evento `aceptado`) | Aceptar = está en preparación. No hay un estado "aceptado" separado                                       |
| `listo`          | Tu POS                     | Terminado, esperando retiro o despacho. Opcional: si tu flujo pasa directo al repartidor, podés saltearlo |
| `asignado`       | Tu POS o Xenda             | Repartidor asignado. Tu POS puede emitirlo desde `en_preparacion` o `listo`                               |
| `entregado`      | Tu POS                     | Cierra el ciclo                                                                                           |
| `rechazado`      | Tu POS                     | Terminal. Requiere `motivo`                                                                               |
| `cancelado`      | Tu POS o Xenda             | Terminal. Requiere `motivo` cuando lo emite tu POS                                                        |
| `en_camino`      | Xenda                      | Solo pedidos con delivery gestionado por Xenda. Tu POS no lo emite, pero puede verlo al consultar         |

<Info>
  **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.
</Info>

## 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).

<Note>
  **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.
</Note>

## 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:

| ✅ Bien                                        | ❌ Evitar      |
| --------------------------------------------- | ------------- |
| `"Nos quedamos sin dulce de leche granizado"` | `"no hay"`    |
| `"Cerramos más temprano por feriado"`         | `"cerrado"`   |
| `"No llegamos con los pedidos de esta noche"` | `"rechazado"` |

## Pedidos que expiran

En producción, un pedido `pendiente` 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=pendiente` entre un poll y el siguiente.
  Podés consultarlo con `?status=cancelado` si necesitás el detalle.
* Aceptar rápido es parte de la experiencia: mientras antes llegue tu `aceptado`,
  antes recibe el cliente su confirmación.

<Info>
  En el **sandbox** la expiración está desactivada, para que puedas probar con calma.
</Info>
