> ## Documentation Index
> Fetch the complete documentation index at: https://docs.listo.delivery/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Notes on the Listo Partner Delivery API:
> - Every endpoint is under `https://api.listo.delivery/v1/` and authenticates with a bearer API key.
> - This documentation site is at https://docs.listo.delivery. The full machine-readable reference is the OpenAPI document at https://api.listo.delivery/docs/openapi.yaml (served by the API host, not by this site).
> - Any page of this site is also available as raw markdown by appending `.md` to its URL, for example https://docs.listo.delivery/en/guides/webhooks.md. The index of every page is https://docs.listo.delivery/llms.txt and all of them in one file is https://docs.listo.delivery/llms-full.txt.
> - Every page is published in English under https://docs.listo.delivery/en/ and in Spanish under https://docs.listo.delivery/es/, with the same path after the language. The API reference is under https://docs.listo.delivery/api-reference/ in English and https://docs.listo.delivery/es/api-reference/ in Spanish.
> - To debug an integration yourself: `GET /v1/request_logs` lists the calls your keys made with what you sent and what was answered, `GET /v1/events` lists the events Listo emitted, `GET /v1/webhook_deliveries` lists every attempt to deliver them, `POST /v1/events/{id}/resend` sends one event again and `POST /v1/test_webhooks` sends a sample event (`"test": true`). The page https://docs.listo.delivery/en/guides/debugging describes them. A resent event is a snapshot from when it happened; `GET /v1/deliveries` is still how you recover current state.
> - Every error response has `error.doc_url`, a page that explains that error code and what to do, and `error.request_id`, the same value as the `X-Request-Id` response header. All the pages are listed at https://docs.listo.delivery/en/errors. Filter `GET /v1/request_logs` with `request_id` to read the logged call.
> - A `409 account_exists` from `POST /v1/stores` means the restaurant already has its own Listo account: connect it instead of creating it, as the page https://docs.listo.delivery/en/guides/connect-existing-account describes.
> - Every live store carries one Plan Listo, charged to the partner. The exception is a connected restaurant that had already paid its current month: it keeps paying its own plan until its next renewal, shown as `paid_by: "store"` with the handover date in `pending_paid_by_on`. A `402 plan_required` from a quote, a delivery create or a retry means the store's plan is not paid or has ended; the page https://docs.listo.delivery/en/guides/plan-and-billing describes the plan, the `plan` block on a store and how to end or restart it.
> - An AI assistant (Claude Code, Cursor, Codex) can act through the same API key at `https://api.listo.delivery/mcp`, an MCP server over Streamable HTTP authenticated with `Authorization: Bearer <API key>`. Every tool runs the matching `/v1/` endpoint, and each one that moves money first previews and then needs a confirmation token; the page https://docs.listo.delivery/en/guides/connect-ai-client lists the tools and describes the two steps.

# De dónde viene un envío

> Por qué en tus tiendas aparecen envíos que tú no creaste, y cómo distinguirlos.

No todos los envíos de tus tiendas los creaste tú. Una tienda cuyo dueño puede
entrar a la consola de comercio puede despachar un pedido desde ahí a mano, y una
tienda que recibe pedidos de sus clientes por WhatsApp tiene un envío por cada
uno, que se crea cuando ella acepta el pedido. Cualquiera de los dos envíos es de
tu cuenta como cualquier otro: sale en tu listado y dispara tus webhooks.

`origin` es el campo que dice cuál de las tres cosas pasó.

```json theme={null}
{
  "id": "dlv_7hK2mQ9xR4tV6bN1cZ8sLwYe",
  "external_id": null,
  "origin": "console"
}
```

| `origin` | Quién creó el envío |
| - | - |
| `api` | Tú, con `POST /v1/deliveries` |
| `console` | La tienda misma, desde la consola de comercio |
| `whatsapp` | Un cliente que pidió a la tienda en un chat de WhatsApp, una vez que la tienda aceptó el pedido |

Esos tres valores son todo el conjunto. Todo envío trae uno, siempre es una cadena
y nunca es `null`, y nunca cambia: un envío se crea una sola vez, por una de las
tres vías, así que la respuesta queda fija desde que el envío existe. Un envío en
`no_courier` que reintentas lo conserva, junto con su id y tu `external_id`.

## Un pedido de consola o de WhatsApp no es una falla de tu integración

Un pedido de consola te llega con `origin: "console"` y `external_id: null`, y
uno de WhatsApp con `origin: "whatsapp"` y `external_id: null`. Ninguno va a
empatar con nada en tu base de datos, porque tú nunca lo metiste ahí. Así se ven
estos pedidos, no es señal de que algo haya salido mal.

Cualquier plataforma donde una persona y un programa crean el mismo tipo de
registro funciona así. Un cargo que alguien captura a mano en un panel igual le
llega a los webhooks del sistema integrado con él, por la misma razón: el
registro es real, la cuenta es tuya, y que te contaran nada más la mitad de lo
que pasó en ella te dejaría las cuentas cortas.

Así que muéstralos o ignóralos, lo que le sirva a lo que estás construyendo. Lo
que no conviene es tratar uno como una falla: nada de alertas, nada de mandarlo a
una cola de errores, y nada de responder con un error a un evento firmado que
entendiste perfectamente.

Y una costumbre que conviene soltar de entrada. No distingas tus pedidos de los
demás buscando un `external_id` ausente. Coincide de casualidad, porque la API
exige uno en cada creación y ni la consola ni un pedido de WhatsApp tienen ese
campo, pero es una deducción armada a partir de otro campo, y `origin` es el
campo que responde la pregunta.

## Con qué dinero se paga un pedido de consola o de WhatsApp

Una tienda solo puede despachar desde la consola cuando es dueña de su dinero,
así que un pedido de consola siempre gasta del saldo de esa tienda y nunca del
tuyo. Tu parte de la tarifa se carga ahí al crear el envío y el efectivo que
cobra el repartidor se abona ahí cuando llega, igual que en un pedido que tú
creaste por la API en esa misma tienda.

Un pedido de WhatsApp se cobra con la misma regla que cualquier otro envío de su
tienda, así que en una tienda que es dueña de su dinero gasta el saldo de esa
tienda y no el tuyo, con el mismo cargo cuando se crea el envío y el mismo abono
del efectivo cuando llega.

Dónde vive el dinero de una tienda y quién puede entrar son un solo ajuste,
`access_tier`, y la tabla está en
[el modelo de dinero](https://docs.listo.delivery/es/concepts/money.md). Solo una tienda en `full` puede
producir un pedido de consola: en `api_only` no puede entrar nadie, y en `wallet` el dueño
llega a las páginas de saldo pero no al despacho. Un pedido de WhatsApp tiene el
mismo límite un paso antes: una tienda recibe pedidos por WhatsApp solo después
de que su dueño conecta un número en los ajustes del asistente de la consola, y
solo una tienda en `full` puede abrirlos. Así que un envío creado mientras la
tienda está en cualquiera de esos dos tiers trae `origin` `"api"`. El tier de
una tienda puede cambiar y un envío conserva el `origin` con el que se creó, así
que lee `origin` del envío y nunca lo deduzcas del tier actual de la tienda.

Aceptar no necesita a una persona en la consola. Una tienda puede hacer que sus
pedidos de WhatsApp se acepten automáticamente, así que un envío `whatsapp` puede
aparecer sin que nadie tenga la sesión abierta.

Eso sirve en los dos sentidos. Si hoy ninguna de tus tiendas está en `full`,
nunca vas a ver un pedido de consola ni de WhatsApp, y dejar el manejo puesto no
te cuesta nada para el día en que alguna lo esté.

## Cómo pedir nada más tus propios pedidos

`GET /v1/deliveries?origin=api` lista solo los envíos que creaste tú,
`origin=console` lista solo los que las tiendas despacharon por su cuenta, y
`origin=whatsapp` lista solo los que sus clientes pidieron por WhatsApp. Se
combina con los otros filtros, así que "los míos, en esta tienda, todavía en
camino" es una sola petición y no un recorrido por todas las páginas
descartando filas conforme llegan.
[`GET /v1/deliveries`](https://docs.listo.delivery/es/api-reference/deliveries/list-deliveries) trae el
conjunto completo de filtros.

En los webhooks no hay equivalente. Cada envío de tus tiendas dispara eventos,
por diseño, así que una suscripción no se puede acotar a un solo origen y el
filtrado ocurre de tu lado. Lee `origin` de `data` y contesta `2xx` en cualquier
caso: el evento se entregó bien, y cualquier otra cosa te gana seis reintentos de
un pedido que ya habías decidido ignorar.

## Dónde aparece `origin`

* En el objeto del envío dondequiera que se devuelva: la creación, una lectura,
  el listado, una cancelación y un reintento.
* En `delivery.status_changed` y `delivery.updated`, cuyo `data` es ese mismo
  objeto completo.
* No en `delivery.courier_location`. Su cuerpo es el objeto delgado de posición y
  no trae campos del envío más allá de los ids, así que vuelve a leer el envío o
  usa lo que ya tenías guardado.
* No en una cotización. Una cotización es un precio y no un pedido, así que
  todavía no tiene de dónde venir.

Cómo enterarte de todo esto sin preguntar está en
[webhooks](https://docs.listo.delivery/es/guides/webhooks.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.