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

# Cotiza un envío

> Cotiza un viaje y reserva ese precio para que lo vincules. El precio se fija en el momento en que pides la cotización: vincula su `id` al crear el envío y al pedido se le cobra el `fee_cents` y el reparto que te mostramos.

La red de repartidores reserva el viaje al crear el envío, y lo que reserva puede diferir un poco del precio cotizado. Reservamos justo la cotización que te mostramos siempre que siga vigente, así que es raro. Cuando pasa, la diferencia aparece en tu historial como su propia línea (`requote_adjustment`, ver `GET /v1/ledger`), negativa cuando el viaje reservado costó más y positiva cuando costó menos. Nunca cambia el `fee_cents`, el reparto ni el total del pedido que ve tu cliente.

Las cotizaciones vencen, y `expires_at` te dice cuándo. Vincular una cotización vencida o ya gastada es un `400`; pide una nueva. Vincularla es opcional, y una creación sin ella se cotiza en línea al precio que haya en ese momento.

`cash_to_collect_cents` es lo que el repartidor cobra en la puerta en un pedido en efectivo: el valor de la mercancía más la parte del cliente de la tarifa.

`business_fee_share` y `business_fee_cap_cents` dicen cómo se reparte la tarifa de envío entre tú y tu cliente. Una cotización `prepaid` es distinta: ya cobraste a tu cliente, así que toda la tarifa es tuya y el reparto queda fijo en 100 sin tope. Una cotización que no nombra `payment_method` se cotiza igual, porque el único envío que puede vincularla es uno `prepaid`. En cualquiera de los dos, un `business_fee_share` distinto de 100 se rechaza con `422
validation_failed` nombrando `business_fee_share`, un `business_fee_cap_cents` válido se ignora (uno que no es número se rechaza primero como error de forma), y una cotización que no envía ninguno se cotiza en 100, sin importar cuál sea el reparto predeterminado de tu tienda. Ese es el reparto que reserva una creación de envío `prepaid`, así que una cotización que quieras vincular a un envío `prepaid` debe nombrar `payment_method: prepaid` o no nombrar ningún método. Para repartir la tarifa con tu cliente, nombra `cash` o `card`.

`vehicle` es `moto` (el predeterminado) o `car`. Un auto es un sedán: podemos garantizar un auto, nunca una camioneta, y hay menos autos que motos, así que uno puede tardar más en asignarse. Un auto agrega un recargo que va DENTRO de `fee_cents` y se reparte como el resto de la tarifa, así que el número que te cotizan es el precio completo; no hay una línea aparte para él.

`manifest.items` es opcional y acepta los mismos elementos `{name, quantity,
size}` que la creación de envío. `size` es uno de `small` (el predeterminado), `medium`, `large` o `xlarge`, y es el único campo de un elemento que puede cambiar el precio: un elemento de tamaño `xlarge` convierte el viaje en auto aunque `vehicle` diga `moto`. Nada más lo hace, ni siquiera el peso. El `vehicle` de la respuesta dice para qué viaje es la tarifa, sin importar qué lo volvió así. Cotiza con el mismo carrito con el que vas a crear el envío: la creación se sujeta al vehículo con el que se fijó el precio de esta cotización.

Un carrito demasiado grande para un solo viaje de repartidor se rechaza con `422
order_too_large`, nombrando `manifest.items`, antes de cotizar nada. Divídelo en dos envíos.

Listo cotiza en pesos mexicanos y entrega en México. Una tienda que resulte estar en otro país se rechaza aquí con `422
unsupported_country`, que es definitivo: no es el `provider_unavailable` reintentable, y ningún reintento de la misma tienda puede funcionar. Solo te encontrarás con él en una tienda que ubicaste tú mismo, con `lat`/`lng`, ya que una tienda que ubicamos nosotros se rechaza al crearla.

Una tienda cuyo punto de recolección no podemos avalar por ahora se rechaza con `409 pickup_point_pending`, porque mientras no esté confirmado, un repartidor podría ir al lugar equivocado. Por lo general la dirección de la tienda acaba de cambiar y la confirmación todavía no llega, pero no siempre, así que no lo leas como "el comercio se mudó". Este SÍ es reintentable: nada en tu solicitud está mal, y la llamada idéntica funciona en cuanto el punto de recolección se confirma. Rechaza la tienda y no el viaje, así que un punto de entrega distinto no ayudará.

Reinténtalo con esperas de minutos, durante un número limitado de intentos, y luego ponlo frente a una persona en lugar de seguir consultando. La mayoría de los cambios se resuelven solos en minutos; unos pocos los detiene algo que solo nuestro equipo puede liberar y tardan bastante más, y esta respuesta no distingue entre los dos. El restaurante también puede desbloquearlo por su cuenta desde su propia consola de Listo, que suele ser la vía más rápida de las dos.

Cuando todos los repartidores cerca del viaje están ocupados, la cotización se rechaza con `409 no_couriers_available` y no se cotiza nada. No es una caída del servicio y nada en tu solicitud está mal: SÍ es reintentable, y la llamada idéntica se cotiza en cuanto un repartidor queda libre, por lo general en minutos. Reinténtalo tras unos minutos, durante un número limitado de intentos, y luego avisa a quien espera el pedido en lugar de seguir consultando. Es la misma palabra que un envío que terminó sin repartidor trae en `failure_reason`.

Una tienda real cuyo Plan Listo no está pagado al día se rechaza con `402
plan_required`, porque la creación rechazaría el envío que cotiza esta cotización. `error.message` nombra el motivo: no hay plan activo, un cobro pendiente, un plan que terminó en una fecha dada, un plan cuyos envíos incluidos del ciclo ya se usaron todos, o una tienda que no puede pedir repartidores en este momento. No es `retryable`: la llamada idéntica falla hasta que el plan se pague o se reinicie, o hasta que el ciclo se renueve. Consulta [Plan y facturación](https://docs.listo.delivery/es/guides/plan-and-billing).




## OpenAPI

````yaml /openapi/es.yaml post /v1/quotes
openapi: 3.1.0
info:
  title: Listo Delivery API
  version: 1.34.0
  description: >
    Cotiza un envío, despáchalo y sigue el recorrido hasta la puerta.


    Cada solicitud se autentica con una llave de API bearer. La llave misma
    decide el modo en el que actúa: una llave de prueba despacha repartidores
    simulados y no mueve dinero, y una llave real despacha repartidores reales.
    Una llave también puede ser de solo lectura: solo puede llamar a GET y HEAD,
    y cualquier otra llamada responde `403 read_only_key`. El dinero siempre va
    en pesos mexicanos y siempre en centavos enteros, y cada marca de tiempo es
    ISO-8601 en UTC.


    Los ids son cadenas opacas con prefijo (`st_` una tienda, `qt_` una
    cotización, `dlv_` un

    envío, `wd_` un retiro, `evt_` un evento, `le_` un movimiento del historial,

    `whd_` un intento de entrega de webhook, `req_` una llamada registrada).
    Trátalos

    como cadenas de longitud ilimitada y nunca los analices.


    Los cambios a v1 son aditivos: pueden aparecer campos nuevos y valores
    nuevos de enumeración, así que ignora lo que no reconozcas en lugar de
    fallar.
servers:
  - url: https://api.listo.delivery
security: []
tags:
  - name: Authentication
    description: Verifica que una llave funciona antes de empezar a construir con ella.
    x-group: Autenticación
  - name: Stores
    description: Las ubicaciones de recolección desde las que despachas.
    x-group: Tiendas
  - name: Account connection
    description: Conectar la cuenta de Listo que ya tiene un restaurante contigo.
    x-group: Conexión de cuenta
  - name: Quotes
    description: Lo que cuesta un envío, cotizado y retenido.
    x-group: Cotizaciones
  - name: Deliveries
    description: Despachar un pedido y seguirlo hasta la puerta.
    x-group: Envíos
  - name: Balance
    description: El saldo prepagado del que salen tus envíos.
    x-group: Saldo
  - name: Withdrawals
    description: Sacar dinero de ese saldo hacia tu banco.
    x-group: Retiros
  - name: Card onboarding
    description: Conectar la cuenta que recibe los pagos con tarjeta.
    x-group: Alta de cobros con tarjeta
  - name: Events
    description: >-
      Los eventos que Listo te envió, al reenviar uno y al enviar un evento de
      prueba a tu endpoint.
    x-group: Eventos
  - name: Webhook deliveries
    description: >-
      Cada intento que hizo Listo de enviar un evento a tu endpoint, y lo que
      respondió tu endpoint.
    x-group: Entregas de webhook
  - name: Request logs
    description: >-
      Cada llamada que hicieron tus llaves a esta API, con lo que enviaste y con
      lo que respondimos.
    x-group: Registro de solicitudes
  - name: Ledger
    x-group: Historial
  - name: Webhooks
    x-group: Webhooks
paths:
  /v1/quotes:
    post:
      tags:
        - Quotes
      summary: Cotiza un envío
      description: >
        Cotiza un viaje y reserva ese precio para que lo vincules. El precio se
        fija en el momento en que pides la cotización: vincula su `id` al crear
        el envío y al pedido se le cobra el `fee_cents` y el reparto que te
        mostramos.


        La red de repartidores reserva el viaje al crear el envío, y lo que
        reserva puede diferir un poco del precio cotizado. Reservamos justo la
        cotización que te mostramos siempre que siga vigente, así que es raro.
        Cuando pasa, la diferencia aparece en tu historial como su propia línea
        (`requote_adjustment`, ver `GET /v1/ledger`), negativa cuando el viaje
        reservado costó más y positiva cuando costó menos. Nunca cambia el
        `fee_cents`, el reparto ni el total del pedido que ve tu cliente.


        Las cotizaciones vencen, y `expires_at` te dice cuándo. Vincular una
        cotización vencida o ya gastada es un `400`; pide una nueva. Vincularla
        es opcional, y una creación sin ella se cotiza en línea al precio que
        haya en ese momento.


        `cash_to_collect_cents` es lo que el repartidor cobra en la puerta en un
        pedido en efectivo: el valor de la mercancía más la parte del cliente de
        la tarifa.


        `business_fee_share` y `business_fee_cap_cents` dicen cómo se reparte la
        tarifa de envío entre tú y tu cliente. Una cotización `prepaid` es
        distinta: ya cobraste a tu cliente, así que toda la tarifa es tuya y el
        reparto queda fijo en 100 sin tope. Una cotización que no nombra
        `payment_method` se cotiza igual, porque el único envío que puede
        vincularla es uno `prepaid`. En cualquiera de los dos, un
        `business_fee_share` distinto de 100 se rechaza con `422

        validation_failed` nombrando `business_fee_share`, un
        `business_fee_cap_cents` válido se ignora (uno que no es número se
        rechaza primero como error de forma), y una cotización que no envía
        ninguno se cotiza en 100, sin importar cuál sea el reparto
        predeterminado de tu tienda. Ese es el reparto que reserva una creación
        de envío `prepaid`, así que una cotización que quieras vincular a un
        envío `prepaid` debe nombrar `payment_method: prepaid` o no nombrar
        ningún método. Para repartir la tarifa con tu cliente, nombra `cash` o
        `card`.


        `vehicle` es `moto` (el predeterminado) o `car`. Un auto es un sedán:
        podemos garantizar un auto, nunca una camioneta, y hay menos autos que
        motos, así que uno puede tardar más en asignarse. Un auto agrega un
        recargo que va DENTRO de `fee_cents` y se reparte como el resto de la
        tarifa, así que el número que te cotizan es el precio completo; no hay
        una línea aparte para él.


        `manifest.items` es opcional y acepta los mismos elementos `{name,
        quantity,

        size}` que la creación de envío. `size` es uno de `small` (el
        predeterminado), `medium`, `large` o `xlarge`, y es el único campo de un
        elemento que puede cambiar el precio: un elemento de tamaño `xlarge`
        convierte el viaje en auto aunque `vehicle` diga `moto`. Nada más lo
        hace, ni siquiera el peso. El `vehicle` de la respuesta dice para qué
        viaje es la tarifa, sin importar qué lo volvió así. Cotiza con el mismo
        carrito con el que vas a crear el envío: la creación se sujeta al
        vehículo con el que se fijó el precio de esta cotización.


        Un carrito demasiado grande para un solo viaje de repartidor se rechaza
        con `422

        order_too_large`, nombrando `manifest.items`, antes de cotizar nada.
        Divídelo en dos envíos.


        Listo cotiza en pesos mexicanos y entrega en México. Una tienda que
        resulte estar en otro país se rechaza aquí con `422

        unsupported_country`, que es definitivo: no es el `provider_unavailable`
        reintentable, y ningún reintento de la misma tienda puede funcionar.
        Solo te encontrarás con él en una tienda que ubicaste tú mismo, con
        `lat`/`lng`, ya que una tienda que ubicamos nosotros se rechaza al
        crearla.


        Una tienda cuyo punto de recolección no podemos avalar por ahora se
        rechaza con `409 pickup_point_pending`, porque mientras no esté
        confirmado, un repartidor podría ir al lugar equivocado. Por lo general
        la dirección de la tienda acaba de cambiar y la confirmación todavía no
        llega, pero no siempre, así que no lo leas como "el comercio se mudó".
        Este SÍ es reintentable: nada en tu solicitud está mal, y la llamada
        idéntica funciona en cuanto el punto de recolección se confirma. Rechaza
        la tienda y no el viaje, así que un punto de entrega distinto no
        ayudará.


        Reinténtalo con esperas de minutos, durante un número limitado de
        intentos, y luego ponlo frente a una persona en lugar de seguir
        consultando. La mayoría de los cambios se resuelven solos en minutos;
        unos pocos los detiene algo que solo nuestro equipo puede liberar y
        tardan bastante más, y esta respuesta no distingue entre los dos. El
        restaurante también puede desbloquearlo por su cuenta desde su propia
        consola de Listo, que suele ser la vía más rápida de las dos.


        Cuando todos los repartidores cerca del viaje están ocupados, la
        cotización se rechaza con `409 no_couriers_available` y no se cotiza
        nada. No es una caída del servicio y nada en tu solicitud está mal: SÍ
        es reintentable, y la llamada idéntica se cotiza en cuanto un repartidor
        queda libre, por lo general en minutos. Reinténtalo tras unos minutos,
        durante un número limitado de intentos, y luego avisa a quien espera el
        pedido en lugar de seguir consultando. Es la misma palabra que un envío
        que terminó sin repartidor trae en `failure_reason`.


        Una tienda real cuyo Plan Listo no está pagado al día se rechaza con
        `402

        plan_required`, porque la creación rechazaría el envío que cotiza esta
        cotización. `error.message` nombra el motivo: no hay plan activo, un
        cobro pendiente, un plan que terminó en una fecha dada, un plan cuyos
        envíos incluidos del ciclo ya se usaron todos, o una tienda que no puede
        pedir repartidores en este momento. No es `retryable`: la llamada
        idéntica falla hasta que el plan se pague o se reinicie, o hasta que el
        ciclo se renueve. Consulta [Plan y
        facturación](https://docs.listo.delivery/es/guides/plan-and-billing).
      operationId: createQuote
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateQuoteRequest'
            example:
              store_id: st_4bR8kM2wQ7xT1nV5cZ9pLdYe
              dropoff:
                street: Blvd. Puerta de Hierro 4965, Zapopan, Jalisco 45116
                lat: 20.709395
                lng: -103.413393
                apt_unit: Depto 4B
              payment_method: cash
              order_value_cents: 19600
              business_fee_share: 100
              business_fee_cap_cents: 3000
              vehicle: car
              manifest:
                items:
                  - name: Tacos al pastor
                    quantity: 2
                  - name: Refrigerador
                    quantity: 1
                    size: xlarge
              pickup_ready_at: '2026-07-29T00:25:00Z'
        required: true
      responses:
        '201':
          description: Creado.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
              example:
                id: qt_5nW3jP8vT2xQ6bM9cZ1sRdKe
                fee_cents: 6844
                business_fee_cents: 6844
                customer_fee_cents: 0
                cash_to_collect_cents: null
                currency: MXN
                pickup_duration_min: 12
                dropoff_eta_at: '2026-07-28T23:11:19Z'
                expires_at: '2026-07-28T22:36:55Z'
                test: true
                created_at: '2026-07-28T22:25:00Z'
                vehicle: moto
        '401':
          description: >-
            La llave de API no existe, fue revocada o no es válida para este
            modo (`invalid_api_key`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: invalid_api_key
                  message: The API key is missing, revoked, or not valid for this mode.
                  param: null
                  retryable: false
                  doc_url: https://docs.listo.delivery/en/errors/invalid_api_key
                  request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
        '403':
          description: >-
            La llave es válida y es de solo lectura (`read_only_key`), así que
            puede leer pero no crear, cambiar ni cancelar nada. Usa una llave
            emitida sin la opción de solo lectura.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                read_only_key:
                  value:
                    error:
                      code: read_only_key
                      message: >-
                        This API key is read-only. Use a key without the
                        read-only setting to create, change or cancel anything.
                      param: null
                      retryable: false
                      doc_url: https://docs.listo.delivery/en/errors/read_only_key
                      request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
        '404':
          description: >-
            Ningún objeto con ese id existe para esta llave (`not_found`). Los
            objetos de otra cuenta son indistinguibles de los que nunca
            existieron.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: not_found
                  message: No resource with that id exists for this API key.
                  param: null
                  retryable: false
                  doc_url: https://docs.listo.delivery/en/errors/not_found
                  request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
        '409':
          description: >-
            La solicitud entra en conflicto con el estado actual. El objeto ya
            no está en un estado que permita esto (`not_cancellable`,
            `not_reschedulable`, `not_retriable`, `not_editable`,
            `not_refundable`, `not_reactivatable`, `plan_ended`), la cancelación
            no se completó (`cancel_failed`), el cobro del plan aún está en el
            banco (`charge_in_progress`), la llave de idempotencia se reutilizó
            con otro cuerpo (`idempotency_conflict`, que ningún reintento
            corrige), la llave de idempotencia aún la retiene la solicitud que
            la envió primero (`idempotency_conflict`, y una vez que esa
            solicitud respondió, la misma llamada con la misma llave repite su
            respuesta), no hay URL de webhook configurada para el modo de la
            llave, así que no hay a dónde enviar
            (`webhook_endpoint_not_configured`), el evento es una posición del
            repartidor, que nunca se vuelve a enviar (`event_not_resendable`),
            el correo ya tiene una cuenta de Listo (`account_exists`), el punto
            de recolección de la tienda aún se está moviendo
            (`pickup_point_pending`), o ningún repartidor está libre para este
            viaje en este momento (`no_couriers_available`). Vale la pena
            repetirla sin cambios después de unos minutos: `cancel_failed`,
            `charge_in_progress`, `pickup_point_pending`,
            `no_couriers_available`, y una llamada rechazada porque su llave de
            idempotencia sigue retenida (repítela con la misma llave). Cualquier
            otro rechazo aquí requiere que primero cambien la solicitud o el
            objeto.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: pickup_point_pending
                  message: >-
                    This store's pickup point is not confirmed yet, so no
                    courier can be requested from it. Retry the same request
                    shortly.
                  param: null
                  retryable: true
                  doc_url: https://docs.listo.delivery/en/errors/pickup_point_pending
                  request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
        '422':
          description: >-
            La solicitud se entendió y se rechazó. `error.code` dice por qué y
            `error.param` nombra el campo con el problema cuando aplica.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: cash_over_cap
                  message: >-
                    The cash amount is over the collection limit. Use card
                    instead.
                  param: null
                  retryable: false
                  doc_url: https://docs.listo.delivery/en/errors/cash_over_cap
                  request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
        '503':
          description: >-
            El despacho no está disponible por ahora (`provider_unavailable`).
            Reintenta pronto.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: provider_unavailable
                  message: >-
                    Dispatch is temporarily unavailable. Nothing was created.
                    Retry.
                  param: null
                  retryable: true
                  doc_url: https://docs.listo.delivery/en/errors/provider_unavailable
                  request_id: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
      security:
        - BearerAuth: []
components:
  schemas:
    CreateQuoteRequest:
      type: object
      description: El viaje a cotizar.
      properties:
        store_id:
          type: string
          description: El id `st_` de la tienda de donde recoge el repartidor.
        dropoff:
          type: object
          description: A dónde va el pedido.
          properties:
            street:
              type: string
              description: La dirección completa de la calle, en una sola cadena.
            apt_unit:
              type: string
            lat:
              type: number
              format: double
              minimum: -90
              maximum: 90
              description: Latitud. Envíala junto con `lng`, o ninguna de las dos.
            lng:
              type: number
              format: double
              minimum: -180
              maximum: 180
              description: Longitud. Envíala junto con `lat`, o ninguna de las dos.
          required:
            - street
        payment_method:
          type: string
          enum:
            - prepaid
            - cash
            - card
          description: Cómo paga el cliente.
        order_value_cents:
          type: integer
          minimum: 0
          description: >
            El valor del pedido, en centavos. Obligatorio para una cotización
            `cash`,

            donde es lo que cobra el repartidor.
        business_fee_share:
          type: integer
          minimum: 0
          maximum: 100
          description: >-
            El porcentaje de la tarifa de envío que paga la tienda. Por omisión
            es el de la propia tienda.
        business_fee_cap_cents:
          type: integer
          minimum: 0
          description: Lo máximo que paga la tienda para la tarifa, en centavos.
        pickup_ready_at:
          type: string
          format: date-time
          description: >-
            Cuándo estará listo el pedido, en ISO-8601 en UTC. Debe ser en el
            futuro.
        vehicle:
          type: string
          enum:
            - moto
            - car
          description: Por omisión es `moto`.
        manifest:
          $ref: '#/components/schemas/Manifest'
      required:
        - store_id
        - dropoff
    Quote:
      type: object
      description: >
        Un envío cotizado y apartado por un momento. Pasa `id` a

        `POST /v1/deliveries` como `quote_id` para reservar exactamente a este
        precio.
      properties:
        id:
          type: string
          description: El id de la cotización, con prefijo `qt_`.
          example: qt_5nW3jP8vT2xQ6bM9cZ1sRdKe
        fee_cents:
          type: integer
          description: >
            La tarifa de envío total, en centavos, y el número al que se sujeta
            una reserva

            de esta cotización. `business_fee_cents` más `customer_fee_cents`
            siempre suman esa cifra.
        business_fee_cents:
          type: integer
          description: La parte de la tarifa que paga la tienda.
        customer_fee_cents:
          type: integer
          description: La parte de la tarifa que paga el cliente.
        cash_to_collect_cents:
          type:
            - integer
            - 'null'
          description: >
            Lo que cobra el repartidor en la puerta en un pedido en efectivo: el
            valor del

            pedido más la parte de la tarifa que paga el cliente. Null en toda
            cotización

            que no sea en efectivo, lo cual no es lo mismo que `0` (un pedido en
            efectivo

            que no cobra nada).
        currency:
          type: string
          enum:
            - MXN
          description: Siempre `MXN`; el dinero va en centavos enteros.
        pickup_duration_min:
          type:
            - integer
            - 'null'
          description: >
            Minutos hasta que se espera un repartidor en la tienda, cuando la
            cotización

            regresó con una estimación. Null en otro caso.
        dropoff_eta_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Cuándo se espera el pedido en la puerta, cuando la cotización
            regresó con una estimación. Null en otro caso.
        expires_at:
          type: string
          format: date-time
          description: >
            El plazo para reservar este precio. Pasado ese plazo, una creación
            responde

            `quote_expired` y tienes que volver a cotizar.
        test:
          type: boolean
          description: Si la cotización pertenece al mundo de pruebas.
        created_at:
          type: string
          format: date-time
        vehicle:
          type: string
          enum:
            - moto
            - car
          description: >
            Para qué se armó este precio: `car` cuando pediste uno o un

            artículo tiene tamaño `xlarge`, `moto` en otro caso. Siempre
            presente.
          example: moto
      required:
        - id
        - fee_cents
        - business_fee_cents
        - customer_fee_cents
        - cash_to_collect_cents
        - vehicle
        - currency
        - pickup_duration_min
        - dropoff_eta_at
        - expires_at
        - test
        - created_at
    ErrorResponse:
      type: object
      description: El cuerpo de toda respuesta 4xx y 5xx de esta API.
      properties:
        error:
          $ref: '#/components/schemas/Error'
      required:
        - error
    Manifest:
      type:
        - object
        - 'null'
      description: >
        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.
      properties:
        items:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/ManifestItem'
    Error:
      type: object
      description: >
        Cómo se ve todo rechazo y toda falla. `code` es el único

        campo en el que decidir; `message` es para una persona que lee un
        registro y puede

        cambiar de redacción o de idioma sin aviso.
      properties:
        code:
          type: string
          description: >
            Un nombre estable y legible por máquina de lo que salió mal, como

            `validation_failed`, `not_found` o `insufficient_balance`. Decide

            con base en esto y nunca en `message`. La lista crece sin romper
            nada: trata

            un código que no conozcas como el fallo genérico que indica su
            código de estado.

            Cada código tiene una página en `doc_url`.
          example: validation_failed
        message:
          type: string
          description: |
            Una oración para quien depura. Puede cambiar de redacción o de
            idioma en cualquier momento, así que nunca la uses para comparar.
          example: order_value_cents is required.
        param:
          type:
            - string
            - 'null'
          description: >
            El campo de la solicitud al que se refiere el rechazo, cuando
            aplica, escrito

            como lo enviaste (`dropoff.street`, `manifest.items`). Null cuando
            la

            falla no se refiere a un solo campo.
          example: order_value_cents
        retryable:
          type: boolean
          description: >
            Si volver a enviar la misma solicitud podría tener éxito. `false`

            significa que nunca lo tendrá sin un cambio de tu lado o en el
            mundo.
          example: false
        doc_url:
          type: string
          format: uri
          description: La página de documentación de este `code`.
          example: https://docs.listo.delivery/en/errors/validation_failed
        request_id:
          type: string
          description: >
            Nuestro id de esta solicitud, el mismo valor que el encabezado de
            respuesta

            `X-Request-Id`. Cítalo a soporte, y filtra

            `GET /v1/request_logs` por él.
          example: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
      required:
        - code
        - message
        - param
        - retryable
        - doc_url
        - request_id
    ManifestItem:
      type: object
      description: >-
        Una línea de la lista descriptiva de artículos que se envía al
        repartidor.
      properties:
        name:
          type: string
          description: Qué es el artículo.
        quantity:
          type: integer
          minimum: 1
          description: Cuántas unidades. Un número entero positivo.
        size:
          type:
            - string
            - 'null'
          enum:
            - small
            - medium
            - large
            - xlarge
            - null
          description: |
            El tamaño del artículo. Omítelo para `small`. Un artículo `xlarge`
            hace que el envío sea en auto.
      required:
        - name
        - quantity
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        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.

````

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