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

# List your ledger entries

> Every movement on your balance, newest first, keyset-paginated. This is
the reconciliation surface: close a period by walking it rather than by
adding up webhook events, so an event you missed, or one you had resent,
changes nothing about what you can rebuild.

`amount_cents` is signed, credits positive and debits negative, which is
what lets a page sum to the movement in your balance across it. Read the
direction off that sign and never off `type`.

`type` says where a movement came from. The pair worth knowing is the
one a wasted trip produces:

- `provider_charge` is the delivery fee billed for a late cancellation
  or a return trip, one fee per leg that was driven, less your own
  store markup. Negative, and tied to the order that caused it. **This
  amount changed on 2026-08-29**: it used to be what the wasted trip
  cost Listo, so expect larger values on the same orders from that date
  onward. The row itself is unchanged.
- `provider_charge_reversal` is that charge credited back in full, when
  the cost turns out not to have been owed. Positive, and posted as its
  own row against the same `delivery_id` rather than as a reduction of
  the original charge, so what you were billed and what came back are
  both still readable. It can arrive weeks after the charge. Pair the
  two by `delivery_id` and expect equal and opposite amounts.

A third value can appear on the same order and is a different amount
under a different heading:

- `order_value_reimbursement` is the value of an order a courier
  collected that reached nobody, credited after we claim it. Positive,
  tied to the order it belongs to, and NOT paired with any debit on this
  ledger: the order's value never moved through your balance, so there
  is nothing to net it against. It is decided case by case and is not
  guaranteed, so never derive it from the order total or expect one per
  incident.
- `listo_charge_correction` is a charge Listo made in error and gave
  back: a `provider_charge` that turned out not to be yours to pay.
  Positive, tied to the order it corrects, and posted as its own row
  beside the original charge, never as a reduction of it. Pair it with
  the charge by `delivery_id`; it can be less than the charge, and an
  order can carry more than one. It is decided case by case, so never
  derive it from a charge or expect one per charge.
- `requote_adjustment` is the difference between the fee your order was
  charged and the fee the courier network booked for its trip, when the
  two are not the same. Signed: negative when the booked trip cost more
  than you were charged, positive when it cost less. Tied to the order,
  posted as its own row beside the order's own charge and never as a
  rewrite of it, and a retry of the same order trues it up to the trip
  finally booked rather than adding another. It is not paired with any
  other row, and it is uncommon.

One more is money you earn, and it is a credit:

- `developer_share` is what you earn on a delivered trip of your own store,
  credited to you when the trip is delivered. Positive, and tied to the
  order it belongs to. A trip that is canceled or returned earns none.

Two more are a store's Plan Listo, paid from your balance:

- `plan_charge` is one month of a store's plan, IVA included. Negative.
  A month paid by card writes no row, because it never touched the
  balance.
- `plan_extra_charge` is the WhatsApp assistant's conversations past
  what a `full` store's plan includes, charged to you with that store's
  plan. Negative.

`store_id` names the store a movement belongs to, on every row: the
store of the order, or the store whose plan was paid. It is `null` when
a movement belongs to no single store, such as a top-up or a withdrawal.

This vocabulary GROWS. New values can appear in any release, because v1
changes additively and a movement you cannot yet name is still money
that moved. So branch on the values you know and let the rest fall
through: count an unfamiliar `type` toward the balance, show it, and do
not drop it or reject it. Rows you discard are the difference between
your books and `GET /v1/balance`.




## OpenAPI

````yaml /openapi/en.yaml get /v1/ledger
openapi: 3.1.0
info:
  title: Listo Delivery API
  version: 1.34.0
  description: |
    Quote a delivery, dispatch it, and follow it to the door.

    Every request authenticates with a bearer API key. The key itself decides
    the world it acts in: a test key dispatches simulated couriers and moves no
    money, a live key dispatches real ones. A key can also be read-only: it
    may call GET and HEAD and nothing else, and any other call answers
    `403 read_only_key`. Money is always in Mexican pesos and
    always in integer cents, and every timestamp is ISO-8601 in UTC.

    Ids are opaque prefixed strings (`st_` a store, `qt_` a quote, `dlv_` a
    delivery, `wd_` a withdrawal, `evt_` an event, `le_` a ledger entry,
    `whd_` a webhook delivery attempt, `req_` a logged request). Treat
    them as strings of unbounded length and never parse them.

    Changes to v1 are additive: new fields and new enum values can appear, so
    ignore what you do not recognise rather than failing on it.
servers:
  - url: https://api.listo.delivery
security: []
tags:
  - name: Authentication
    description: Checking that a key works before you build against it.
  - name: Stores
    description: The pickup locations you dispatch from.
  - name: Account connection
    description: Connecting a restaurant's existing Listo account to you.
  - name: Quotes
    description: What a delivery costs, priced and held.
  - name: Deliveries
    description: Dispatching an order and following it to the door.
  - name: Balance
    description: The prepaid balance your deliveries draw on.
  - name: Withdrawals
    description: Moving money out of that balance to your bank.
  - name: Card onboarding
    description: Connecting the account that takes card payments.
  - name: Events
    description: >-
      The events Listo sent you, resending one, and sending a test event to your
      endpoint.
  - name: Webhook deliveries
    description: >-
      Every attempt Listo made to send an event to your endpoint, and what came
      back.
  - name: Request logs
    description: >-
      Every call your keys made to this API, with what you sent and what we
      answered.
paths:
  /v1/ledger:
    get:
      tags:
        - Ledger
      summary: List your ledger entries
      description: >
        Every movement on your balance, newest first, keyset-paginated. This is

        the reconciliation surface: close a period by walking it rather than by

        adding up webhook events, so an event you missed, or one you had resent,

        changes nothing about what you can rebuild.


        `amount_cents` is signed, credits positive and debits negative, which is

        what lets a page sum to the movement in your balance across it. Read the

        direction off that sign and never off `type`.


        `type` says where a movement came from. The pair worth knowing is the

        one a wasted trip produces:


        - `provider_charge` is the delivery fee billed for a late cancellation
          or a return trip, one fee per leg that was driven, less your own
          store markup. Negative, and tied to the order that caused it. **This
          amount changed on 2026-08-29**: it used to be what the wasted trip
          cost Listo, so expect larger values on the same orders from that date
          onward. The row itself is unchanged.
        - `provider_charge_reversal` is that charge credited back in full, when
          the cost turns out not to have been owed. Positive, and posted as its
          own row against the same `delivery_id` rather than as a reduction of
          the original charge, so what you were billed and what came back are
          both still readable. It can arrive weeks after the charge. Pair the
          two by `delivery_id` and expect equal and opposite amounts.

        A third value can appear on the same order and is a different amount

        under a different heading:


        - `order_value_reimbursement` is the value of an order a courier
          collected that reached nobody, credited after we claim it. Positive,
          tied to the order it belongs to, and NOT paired with any debit on this
          ledger: the order's value never moved through your balance, so there
          is nothing to net it against. It is decided case by case and is not
          guaranteed, so never derive it from the order total or expect one per
          incident.
        - `listo_charge_correction` is a charge Listo made in error and gave
          back: a `provider_charge` that turned out not to be yours to pay.
          Positive, tied to the order it corrects, and posted as its own row
          beside the original charge, never as a reduction of it. Pair it with
          the charge by `delivery_id`; it can be less than the charge, and an
          order can carry more than one. It is decided case by case, so never
          derive it from a charge or expect one per charge.
        - `requote_adjustment` is the difference between the fee your order was
          charged and the fee the courier network booked for its trip, when the
          two are not the same. Signed: negative when the booked trip cost more
          than you were charged, positive when it cost less. Tied to the order,
          posted as its own row beside the order's own charge and never as a
          rewrite of it, and a retry of the same order trues it up to the trip
          finally booked rather than adding another. It is not paired with any
          other row, and it is uncommon.

        One more is money you earn, and it is a credit:


        - `developer_share` is what you earn on a delivered trip of your own
        store,
          credited to you when the trip is delivered. Positive, and tied to the
          order it belongs to. A trip that is canceled or returned earns none.

        Two more are a store's Plan Listo, paid from your balance:


        - `plan_charge` is one month of a store's plan, IVA included. Negative.
          A month paid by card writes no row, because it never touched the
          balance.
        - `plan_extra_charge` is the WhatsApp assistant's conversations past
          what a `full` store's plan includes, charged to you with that store's
          plan. Negative.

        `store_id` names the store a movement belongs to, on every row: the

        store of the order, or the store whose plan was paid. It is `null` when

        a movement belongs to no single store, such as a top-up or a withdrawal.


        This vocabulary GROWS. New values can appear in any release, because v1

        changes additively and a movement you cannot yet name is still money

        that moved. So branch on the values you know and let the rest fall

        through: count an unfamiliar `type` toward the balance, show it, and do

        not drop it or reject it. Rows you discard are the difference between

        your books and `GET /v1/balance`.
      operationId: listLedgerEntries
      parameters:
        - name: cursor
          in: query
          required: false
          schema:
            type: string
          example: 1785628920000000-1024
        - name: delivery_id
          in: query
          required: false
          schema:
            type: string
          example: dlv_7hK2mQ9xR4tV6bN1cZ8sLwYe
        - name: type
          in: query
          required: false
          schema:
            type: string
          example: provider_charge
      responses:
        '200':
          description: The request succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LedgerEntryList'
              example:
                data:
                  - id: le_3kR7pM1xV9tB4nQ6cW2sZdYe
                    type: provider_charge
                    amount_cents: -5800
                    delivery_id: dlv_7hK2mQ9xR4tV6bN1cZ8sLwYe
                    store_id: st_4bR8kM2wQ7xT1nV5cZ9pLdYe
                    test: false
                    occurred_at: '2026-08-01T12:00:00Z'
                has_more: false
                cursor: null
        '401':
          description: >-
            The API key is missing, revoked, or not valid for this mode
            (`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
        '404':
          description: >-
            No object with that id exists for this key (`not_found`). Another
            account's objects are indistinguishable from ones that never
            existed.
          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
      security:
        - BearerAuth: []
components:
  schemas:
    LedgerEntryList:
      type: object
      description: One page of ledger entries, newest first.
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/LedgerEntry'
        has_more:
          type: boolean
          description: True when a further page exists.
        cursor:
          type:
            - string
            - 'null'
          description: Pass as `cursor` to read the next page. Null on the last page.
      required:
        - data
        - has_more
        - cursor
    ErrorResponse:
      type: object
      description: The body of every 4xx and 5xx answer on this API.
      properties:
        error:
          $ref: '#/components/schemas/Error'
      required:
        - error
    LedgerEntry:
      type: object
      description: One movement on a balance. Credits are positive, debits negative.
      properties:
        id:
          type: string
          description: The entry id, `le_` prefixed.
          example: le_3kR7pM1xV9tB4nQ6cW2sZdYe
        type:
          type: string
          description: |
            Where the movement came from, such as `provider_charge`,
            `provider_charge_reversal`, `developer_share`, `plan_charge` or
            `requote_adjustment`. The vocabulary GROWS: it is deliberately a
            plain string, not a closed list, so branch on the values you know
            and count an unfamiliar one toward the balance. `GET /v1/ledger`
            describes each value.
          example: provider_charge
        amount_cents:
          type: integer
          description: Signed centavos. Read the direction off the sign, never off `type`.
        delivery_id:
          type:
            - string
            - 'null'
          description: >-
            The `dlv_` id the movement stems from. Null for a top-up, a
            withdrawal or an adjustment.
        store_id:
          type:
            - string
            - 'null'
          description: >-
            The `st_` id of the store the movement belongs to. Null when it
            belongs to no single store.
        test:
          type: boolean
        occurred_at:
          type: string
          format: date-time
          description: When the money moved.
      required:
        - id
        - type
        - amount_cents
        - delivery_id
        - store_id
        - test
        - occurred_at
    Error:
      type: object
      description: |
        What every refusal and every failure looks like. `code` is the only
        field to branch on; `message` is for a human reading a log and may
        change wording or language without notice.
      properties:
        code:
          type: string
          description: |
            A stable, machine-readable name for what went wrong, such as
            `validation_failed`, `not_found` or `insufficient_balance`. Branch
            on this and never on `message`. The set grows additively: handle a
            code you do not know as the generic failure its status code says it
            is. Every code has a page under `doc_url`.
          example: validation_failed
        message:
          type: string
          description: |
            A sentence for the person debugging. Free to change wording or
            language, so never match on it.
          example: order_value_cents is required.
        param:
          type:
            - string
            - 'null'
          description: |
            The request field the refusal is about, when one applies, spelled
            as you sent it (`dropoff.street`, `manifest.items`). Null when the
            failure is not about one field.
          example: order_value_cents
        retryable:
          type: boolean
          description: |
            Whether sending the identical request again could succeed. `false`
            means it never will without a change on your side or in the world.
          example: false
        doc_url:
          type: string
          format: uri
          description: The documentation page for this `code`.
          example: https://docs.listo.delivery/en/errors/validation_failed
        request_id:
          type: string
          description: |
            Our id for this request, the same value as the `X-Request-Id`
            response header. Quote it to support, and filter
            `GET /v1/request_logs` by it.
          example: 0b1f6c9a-7e2d-4c53-9a41-5d8e3f2a6b10
      required:
        - code
        - message
        - param
        - retryable
        - doc_url
        - request_id
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your API key, sent as `Authorization: Bearer <key>`. Live and test keys
        are separate; the key you send decides which world the call acts in. To
        try calls, use a test key (it starts with `lst_test_`): no real courier
        is sent and no real money moves, but webhooks fire and the
        `dropoff.phone` you give can receive WhatsApp messages, so use your own
        number. A live key (it starts with `lst_live_`) books and charges real
        deliveries.

````

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