Saltar al contenido principal
POST
Crea un envío

Autorizaciones

Authorization
string
header
requerido

Tu llave de API, enviada como Authorization: Bearer <key>. Las llaves reales y de prueba son distintas; la llave que envías decide en qué modo actúa la llamada. Para probar llamadas, usa una llave de prueba (empieza con lst_test_): no se envía ningún repartidor real y no se mueve dinero real, pero los webhooks se disparan y el dropoff.phone que des puede recibir mensajes de WhatsApp, así que usa tu propio número. Una llave real (empieza con lst_live_) reserva y cobra envíos reales.

Encabezados

Idempotency-Key
string
requerido

Obligatorio: una llamada sin él se rechaza con validation_failed, indicando este encabezado. Genera una llave NUEVA para cada llamada lógica (un UUID sirve bien), de hasta 255 caracteres, y envía la MISMA llave cuando reintentes esa llamada tras un tiempo de espera o una conexión caída. La misma llave con el mismo cuerpo devuelve la respuesta ORIGINAL, con su código de estado incluido, en lugar de volver a hacer el trabajo, durante 24 horas. La misma llave con un cuerpo distinto se rechaza con 409 idempotency_conflict, y también un reintento que llega mientras la primera solicitud aún se procesa (vuelve a intentarlo en un momento). Una llave pertenece a tu cuenta y al modo de la llave de API que la envió (las llaves de producción y de prueba nunca se cruzan), así que el mismo texto de dos cuentas, o de una llave de producción y una de prueba, son dos llaves distintas.

Cuerpo

application/json

El pedido a despachar.

store_id
string
requerido

El id st_ de la tienda de donde recoge el repartidor.

external_id
string
requerido

Tu propia referencia para este pedido. Se devuelve como external_id.

Maximum string length: 255
payment_method
enum<string>
requerido

Cómo paga el cliente.

Opciones disponibles:
prepaid,
cash,
card
order_value_cents
integer
requerido

El valor del pedido, en centavos.

Rango requerido: x >= 0
dropoff
object
requerido

A dónde va el pedido y quién lo recibe.

quote_id
string

El id qt_ de una cotización para reservar a su precio exacto. Sin uno, el envío se cotiza al momento de crearlo.

business_fee_share
integer

El porcentaje de la tarifa de envío que paga la tienda. Por omisión es el de la propia tienda, y se fija en 100 en un pedido prepaid.

Rango requerido: 0 <= x <= 100
business_fee_cap_cents
integer

Lo máximo que paga la tienda para la tarifa, en centavos.

Rango requerido: x >= 0
tip_cents
integer

Una propina para el repartidor, en centavos, de hasta 100000. Solo se permite en un pedido prepaid.

Rango requerido: 0 <= x <= 100000
handoff
enum<string>

Dónde le entrega el repartidor el pedido. Por omisión es meet_at_door.

Opciones disponibles:
meet_at_door,
leave_at_door,
meet_outside
manifest
object | null

La lista descriptiva de artículos para el repartidor. El dinero nunca sale de ella; su único efecto en el viaje es que un artículo xlarge lo convierte en auto. Ausente, null, {} y {"items": null} significan todos que no hay carrito.

verification
object

Comprobante que el cliente debe dar al repartidor.

pickup_ready_at
string<date-time>

Cuándo estará listo el pedido, en ISO-8601 en UTC, entre 10 minutos y 29 días a partir de ahora. Omítelo para despachar ahora.

vehicle
enum<string>

Por omisión es moto, o el de la cotización cuando reservas una.

Opciones disponibles:
moto,
car
simulate
enum<string>

Solo llaves de prueba: el escenario que juega el repartidor simulado. Una llave de producción que lo envíe es rechazada.

Opciones disponibles:
returned,
no_courier,
delayed_pickup

Respuesta

Creado.

La forma de un envío: cada campo que puede llevar el objeto, con la nulabilidad que realmente tiene cada uno. Es la respuesta de cada operación que responde un envío (la creación, la consulta, una fila de lista, la reprogramación, la cancelación, el reintento y el reembolso) y el data de cada evento completo de envío, así que UN tipo sostiene todos ellos.

Cada operación devuelve el objeto completo. Un campo que una llamada dada todavía no puede tener está presente y es null en lugar de faltar: una respuesta de creación tiene courier en null, porque todavía no se asigna ningún repartidor, y una reprogramación solo responde con un pedido que sigue programado, así que su delivered_at es null.

El dinero va en centavos enteros, las marcas de tiempo son ISO-8601 en UTC, y cada enumeración de abajo es nuestra y no una copia de la de un tercero.

id
string
requerido

El id del envío, con prefijo dlv_.

Ejemplo:

"dlv_7hK2mQ9xR4tV6bN1cZ8sLwYe"

external_id
string | null
requerido

Tu propia referencia del pedido, devuelta exactamente como la enviaste.

Ejemplo:

"order-841"

origin
enum<string>
requerido

Qué vía creó el envío. api es uno que creaste con POST /v1/deliveries. console es uno que la tienda despachó desde la consola de comerciante de Listo, algo que una tienda solo puede hacer en el nivel de acceso full. whatsapp es uno que un cliente pidió a la tienda en un chat, y que la tienda luego aceptó; ningún operador lo escribió en ningún lado.

Siempre está presente, nunca es null, y queda fijo durante toda la vida del envío. Un pedido de consola trae un external_id null, pero lee este campo en lugar de ese null: la referencia faltante es una consecuencia de la vía, no una forma de identificarla.

Opciones disponibles:
api,
console,
whatsapp
Ejemplo:

"api"

code
string
requerido

El código de pedido que citan el repartidor y nuestro soporte. Es único por tienda, no a nivel global, así que nunca identifiques un pedido solo por él.

Ejemplo:

"LS-2048"

status
enum<string>
requerido

delivered, returned y canceled son terminales. no_courier es un callejón sin salida que puedes reintentar o cancelar. Un envío returned es este mismo objeto de principio a fin; no hay un segundo envío para el tramo de regreso.

returning: la entrega falló y el repartidor está llevando el pedido de regreso a la tienda; termina en returned. NO es terminal, y es donde un envío fallido ahora pasa los minutos entre el momento en que el repartidor se rinde en la puerta del cliente y el pedido llega de regreso. returned significa que el pedido ya regresó. Trata returning como un envío vivo: el repartidor sigue en movimiento y los eventos delivery.courier_location siguen llegando para él.

El cargo de regreso se registra cuando el envío entra en returning, no cuando llega a returned, así que charges ya está completo en el evento returning.

awaiting_location: un pedido que la tienda tomó por la consola de Listo o por su asistente de WhatsApp, retenido en espera de la ubicación de entrega. Todavía no se pide un repartidor. El cliente confirma la ubicación con un enlace de mapa o compartiéndola en el chat de WhatsApp, o la tienda la confirma desde su consola. Luego el envío pasa a scheduled o dispatching; a no_courier cuando no se puede pedir un repartidor para él (la ubicación está fuera de la zona donde entrega la tienda, o la tienda misma no puede pedir un repartidor en este momento); o a canceled si el pedido se cancela o la tienda lo cambia a recolección en el mostrador. Un envío que creas por esta API nunca pasa por ese estado.

Opciones disponibles:
awaiting_payment,
awaiting_location,
scheduled,
dispatching,
courier_assigned,
picking_up,
en_route,
returning,
delivered,
returned,
canceled,
no_courier
store_id
string
requerido

El id st_ de la tienda de donde recoge el repartidor.

test
boolean
requerido

Si este pedido vive en el sandbox. Se deriva de la tienda, así que no hay un campo que fijar: una llave de prueba solo puede llegar a tiendas de prueba.

payment
object
requerido

Cómo paga el cliente y en qué estado va el pago.

order_value_cents
integer | null
requerido

El valor de la mercancía que enviaste, sin cambios.

fee_cents
integer
requerido

La tarifa total de envío.

business_fee_cents
integer
requerido

La parte de fee_cents que se te cobra a ti.

customer_fee_cents
integer
requerido

La parte de fee_cents que se cobra al cliente. Siempre suma, junto con business_fee_cents, el total de fee_cents.

tip_cents
integer
requerido

La propina al repartidor que enviaste en este envío, que se paga al repartidor y se pasa tal cual, al costo, sin margen. Deliberadamente FUERA de fee_cents, que es la tarifa de envío a la que suman business_fee_cents y customer_fee_cents. Es 0 cuando no enviaste ninguna, y nunca es null.

currency
enum<string>
requerido
Opciones disponibles:
MXN
quote_id
string | null
requerido

La cotización qt_ que vinculó este pedido, para que puedas ligar el precio que te cotizaron con el pedido que lo gastó. Es null cuando el pedido se cotizó en línea.

pickup
object
requerido

Dónde recoge el repartidor, tomado como instantánea al crear, para que un pedido histórico siga reportando a dónde fue el repartidor de verdad aunque la tienda cambie de nombre o de lugar.

dropoff
object
requerido

A dónde entrega el repartidor, devuelto tal como lo enviaste.

manifest
object | null
requerido

La lista descriptiva de artículos que enviaste, para el repartidor. El dinero nunca sale de ella, con una excepción: un artículo de tamaño xlarge hace que el viaje sea en auto. Es null cuando no enviaste ninguna.

vehicle
enum<string>
requerido

Cómo se cotizó y despachó el viaje: car cuando pediste uno o cuando un artículo tenía tamaño xlarge, moto en los demás casos. El recargo de un auto va dentro de fee_cents. Siempre está presente, nunca es null, y queda fijo durante toda la vida del envío.

No es el vehículo que llegó. Ese es courier.vehicle_type, que puede ser un auto en un viaje moto sin que la tarifa cambie.

Opciones disponibles:
moto,
car
Ejemplo:

"moto"

courier
object | null
requerido

Null hasta que se asigna un repartidor, y después CONGELADO: un envío terminal sigue reportando quién lo llevó.

pickup_eta_at
string<date-time> | null
requerido

Cuándo se espera que el repartidor llegue a la tienda. Es una hora absoluta, así que calcula tu propia cuenta regresiva; una cuenta regresiva calculada aquí ya está desactualizada cuando la lees.

dropoff_eta_at
string<date-time> | null
requerido

Cuándo se espera que el repartidor llegue con el cliente. Es null hasta que hay una estimación, y vuelve a ser null cuando la entrega fallida ya ocurrió (returning, returned): el repartidor entonces regresa el pedido a la tienda, no queda una llegada al cliente que describir, y aquí nunca se publica la hora en que vuelve a la tienda.

tracking_url
string<uri> | null
requerido

La página de seguimiento en vivo, con marca propia, para el cliente: el mapa, el repartidor, el código de entrega y lo que se cobra en la puerta. Es null cuando no hay página a la que apuntar, así que nunca reenvías un enlace muerto.

Hay página desde el momento en que el pedido se despacha, incluida toda la ventana antes de que se asigne un repartidor, y durante 48 horas después de que el pedido se entrega, se cancela o regresa. Es null mientras un pedido sigue retenido esperando pago o esperando un pin de punto de entrega confirmado, y vuelve a ser null cuando pasan esas 48 horas.

Ejemplo:

"https://app.listo.delivery/t/abc123"

verification
object | null
requerido

Está presente solo cuando el pedido trae un PIN de entrega: cuando lo pediste (verification.dropoff_pincode en la creación), o cuando Listo exige un PIN en cada envío de la cuenta de esta tienda, en cuyo caso está presente aunque no lo pediste. pincode es null hasta que el pedido se despacha de verdad, que es cuando se genera el código.

return_verification
object
requerido

El código de devolución. Cuando un pedido no se puede entregar y el repartidor lo regresa a la tienda, el repartidor debe recibir este código en la tienda para entregar el pedido; sin él la devolución no se puede completar. pincode es una cadena de 4 dígitos mientras el envío está en returning, y null en cualquier otro estado (antes de la devolución, y una vez que está en returned). El objeto siempre está presente, así que este campo nunca necesita una verificación de presencia. Llega en delivery.status_changed (el paso a returning) y en delivery.updated, que traen el objeto completo. Un nuevo intento (un reintento) recibe su propio código. Muéstraselo a la tienda, y nunca al cliente.

proof
object | null
requerido

Prueba de entrega. Null a menos que tengamos alguna, y cada campo es null cuando falta esa pieza; una foto sin firma es normal. Las URL son enlaces firmados propios de Listo hacia la copia guardada y son válidas durante 24 horas desde la respuesta (o el webhook) que las trajo: vuelve a pedir GET /v1/deliveries/{id} para obtener un enlace nuevo, o guarda una copia. Una URL es null hasta que Listo tiene su propia copia de la imagen (unos segundos después de que el repartidor la toma); la llegada de la copia se anuncia con un webhook delivery.updated que trae el enlace. Puede venir de un intento de entrega que falló en la puerta, así que por sí sola no prueba que el pedido se entregó: proofs.dropoff.delivered dice cuál. Prefiere proofs, que separa cada momento del viaje.

proofs
object
requerido

La evidencia que dejó el viaje, una entrada por momento. Cada momento es null hasta que sucede (todavía no se capturó nada para él), así que este objeto siempre está presente con sus tres llaves. Un enlace de foto o de firma es el enlace firmado de Listo al archivo guardado, y es null hasta que Listo tiene ese archivo (unos segundos después de que el repartidor toma la foto): el resto del momento, quién firmó, la hora y la distancia, está desde el principio, y cuando el archivo llega un webhook delivery.updated trae el enlace. Cada enlace es válido por 24 horas desde la respuesta (o el webhook) que lo trajo: es un enlace firmado de vida corta, nunca uno permanente. Un socio que necesite la imagen después vuelve a pedir GET /v1/deliveries/{id} para obtener un enlace nuevo, o guarda una copia.

cancellation
object | null
requerido

Quién canceló el pedido, y por qué. Es null en un pedido que no se canceló.

failure_reason
enum<string> | null
requerido

Por qué falló un despacho, agrupado según de qué lado está el problema, para que puedas actuar en lugar de solo reintentar a ciegas. no_couriers_available es el que se puede reintentar. delivery_failed es el cajón general honesto. Es null a menos que se haya registrado una falla.

Opciones disponibles:
no_couriers_available,
address_unreachable,
customer_unavailable,
delivery_failed,
null
charges
object[]
requerido

Lo que se cobra por un viaje que se recorrió pero se desperdició: la tarifa de envío de cada tramo recorrido, menos tu propio margen de tienda. Vacío en casi todos los envíos, y nunca null.

Este monto cambió el 2026-08-29. Antes era lo que le costaba a Listo el viaje desperdiciado, así que espera valores mayores en los mismos pedidos a partir de esa fecha. El campo en sí no cambió.

Siempre está presente en un objeto de envío, así que trata un charges ausente como imposible y no como "sin cargos". Por esa razón está en la lista required de este esquema.

Un cargo puede llegar en el delivery.status_changed final del envío o, cuando el costo se liquida después, en un delivery.updated posterior. No puedes suponer cuál, así que lee este campo en ambos: cobrar en el momento en que un envío llega a su estado terminal cobra de menos en cada pedido cuyo costo llegó tarde.

El mismo movimiento aparece en GET /v1/ledger como una fila con signo, así que allí se lee negativo mientras que amount_cents aquí es positivo.

refunds
object[]
requerido

Cada vez que se devolvió dinero al cliente por este pedido, del más reciente al más antiguo. Vacío en un pedido que nunca se ha reembolsado, y nunca null.

Siempre presente en un objeto de envío, así que trata un refunds ausente como algo imposible, no como "sin reembolsos". Está en la lista required de este esquema por esa razón, igual que charges arriba.

Es una LISTA porque los reembolsos se repiten: un reembolso parcial va seguido de otro reembolso, cada uno con su propio monto, su propio motivo y su propio resultado. Aquí aparece todo reembolso que podemos ver, sin importar quién lo hizo, y por eso la lista vale la pena para conciliar. La cuenta conectada pertenece al comercio de registro (el titular del cargo), que puede reembolsar un cargo en ella sin pasar por nosotros; esos llegan como requested_via: external, y una lista que mostrara solo los reembolsos que tú pediste contradiría en silencio el payment.status de este pedido.

Un reembolso viaja en delivery.updated, nunca en un evento propio.

refunded_cents
integer
requerido

La suma de los reembolsos EXITOSOS de arriba, en centavos de peso mexicano. 0, nunca null, en un pedido al que nada se le haya devuelto. Un reembolso pending no se cuenta, porque el dinero no se ha movido y todavía puede ser rechazado.

Se publica en lugar de dejártelo calcular, porque el arreglo no siempre se puede sumar bien: un reembolso del saldo restante no lleva amount_cents hasta que se confirma, así que sumar la lista lo cuenta como cero y hace que todo el cargo parezca todavía reembolsable. En cambio tomamos ese caso de forma pesimista, como si hubiera consumido todo el saldo restante, porque adivinar a la baja termina reembolsando dos veces a un cliente.

refundable_cents
integer
requerido

Lo que todavía podría devolver un reembolso adicional: lo que pagó el cliente (order_value_cents más customer_fee_cents, que ES el cargo) menos refunded_cents, sin bajar de cero. 0, nunca null.

0 en cualquier pedido sin un pago con tarjeta cobrado detrás, sin importar su valor. El efectivo nunca tocó nuestros rieles de pago, el cliente de un pedido prepagado es tuyo y nosotros no tenemos nada de él, y un pedido que todavía espera pago nunca se cobró, así que en ninguno de estos hay algo que un reembolso pudiera devolver.

Este es el techo contra el que POST /v1/deliveries/{id}/refunds rechaza un amount_cents, así que léelo antes de llamar en lugar de descubrir el límite a partir de un refund_amount_too_large.

support_reference
string | null
requerido

Un identificador corto que citas cuando nos escalas un pedido. Null hasta que el pedido llega a despacho.

Ejemplo:

"2080F"

pickup_ready_at
string<date-time> | null
requerido

La hora de recolección programada que pediste. Es null en un pedido de despacho inmediato.

requested_at
string<date-time> | null
requerido
courier_assigned_at
string<date-time> | null
requerido

Cuándo se observó por primera vez a un repartidor en el intento actual. En realidad es una observación y no un reloj de asignación, porque no se nos publica ningún momento de asignación. Es null en un intento que nunca lo tuvo.

picked_up_at
string<date-time> | null
requerido
delivered_at
string<date-time> | null
requerido
canceled_at
string<date-time> | null
requerido
returned_at
string<date-time> | null
requerido
created_at
string<date-time>
requerido
updated_at
string<date-time>
requerido