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

# The money model

> Who pays for a delivery, and how the balance is kept.

Every amount on this API is an integer count of Mexican peso cents, and every
money-bearing response says so with a `currency` of `"MXN"`. There are no
decimals, no other currency, and no formatted strings: `19600` is
MX\$196.00.

## One fee, split two ways

A delivery costs one number, `fee_cents`. It is the whole cost of moving the
order, computed for that distance, that moment and that payment method.
A trip by car carries its surcharge inside this same number (see
[sending it by car](https://docs.listo.delivery/en/guides/quote-and-create.md#sending-it-by-car)).

That single number is then split between two payers:

```
business_fee_cents + customer_fee_cents = fee_cents
```

always, on the quote and on the delivery alike. You choose the split with
`business_fee_share`, a percentage from 0 to 100 saying how much of the fee
*you* absorb:

* `business_fee_share: 100` means you pay the whole delivery fee and the
  customer pays nothing towards it. Free delivery, from the customer's side.
* `business_fee_share: 0` means the customer pays all of it.
* Anything between splits it.

Each store carries a `default_business_fee_share` so you can set the policy once,
and any single order can override it.

The value of the order itself, `order_value_cents`, is separate from all of
this. Listo never adds the fee into it or takes the fee out of it.

### Capping what you absorb

When your rule is an amount rather than a ratio, send
`business_fee_cap_cents`: an absolute ceiling, in cents, on what you pay.

```
business_fee_cents = min(business_fee_share% of fee_cents, business_fee_cap_cents)
```

The customer still pays the exact remainder, so the two figures sum to
`fee_cents` exactly as before. Every cent the ceiling stops you absorbing is a
cent your customer pays instead.

The common arrangement is `business_fee_share: 100` with a ceiling, which reads
"I cover delivery up to MX$30 and the customer pays anything above that". A
ceiling with a lower share puts a roof on a percentage: `50` with `3000` is
"half the fee, but never more than MX$30".

Send the amount rather than converting it into a percentage yourself. A
percentage is only a ceiling against the fee it was worked out from, so a
converted one breaks as soon as the real fee differs from the one you converted
against. MX$30 of a MX$100 quote is 30%, and 30% of the MX$120 the trip actually
costs is MX$36: over the ceiling you meant to set. Send `3000` and it is applied
to the fee actually being split, whatever that fee turns out to be.

Two things to know:

* There is no store-level default ceiling. A ceiling usually depends on the
  basket, so it is a per-order field rather than a setting you leave standing.
* A ceiling higher than the fee is not an error. It does not bind on that order,
  and the percentage decides the split on its own.

On a cash order a ceiling works against you at the door. See
[cash at the door](https://docs.listo.delivery/en/concepts/cash-at-the-door.md).

## Your share comes off the balance

Your account holds a prepaid balance per mode, and `business_fee_cents` is
debited from it when the delivery is created, before any courier is called.

Everything on that balance can be spent on deliveries the moment it arrives, but
not all of it can be withdrawn straight away: cash your couriers collected and
money you added by card are each held for a period first. See
[balance and withdrawals](https://docs.listo.delivery/en/guides/balance-and-withdrawals.md).

If the balance does not cover it, the create is refused with
`402 insufficient_balance` and nothing is dispatched. That is the whole balance
gate on a create: no credit, no overdraft, and no partial dispatch.

Each live store also carries one Plan Listo, a monthly charge per store. A store
you create is yours to pay from the day you create it in live mode, from this
balance or from a card saved on your account. A restaurant that
[connects to you](https://docs.listo.delivery/en/guides/connect-existing-account.md) with its current
month already paid keeps paying its own plan until its next renewal: its store
reads `paid_by: "store"`, and `pending_paid_by` and `pending_paid_by_on` name the
day the plan passes to you, which is the day of your first charge. If its
current month is unpaid when it connects, the plan passes to you that day: the
month it had not paid is voided, so nobody is charged for it, and one full month
is charged to you that day. If the restaurant cancels its own
plan before the handover, the plan never passes to you.

The plan is a gate of its own: a live store whose plan is left unpaid by
whoever pays it, or has ended, has its quotes and creates refused with
`402 plan_required` whatever the balance holds. A debt the restaurant still owes
on its own plan never stops a store whose plan you pay. A month paid from the
balance appears on `GET /v1/ledger` as a `plan_charge` row naming the store.
See [plan and billing](https://docs.listo.delivery/en/guides/plan-and-billing.md).

The customer's share never touches the balance. It is collected from the
customer directly, folded into what the courier collects on a cash order or
added to the charge on a card order.

A courier tip comes off the balance the same way. `tip_cents` on a `prepaid`
create is debited together with your fee share, as one movement for one order,
and the balance has to cover both or the create is refused. The tip is not part
of `fee_cents` and is never split with your customer, so it changes what you
pay and nothing else. Listo keeps no part of it: the whole amount reaches the
courier. See [quote and create](https://docs.listo.delivery/en/guides/quote-and-create.md) for the
rules on the field itself.

> [!NOTE]
>
> **Prepaid orders are always fully yours**
>
> On `payment_method: prepaid`, the share is always 100 and
> `business_fee_cap_cents` is ignored. Listo never charges the customer on a prepaid
> order, so there is nobody to collect a customer share from, and a ceiling is a
> way of handing part of the fee to exactly that nobody. What happens to a share
> you send depends on where you send it:
>
> * On a **quote**, a `business_fee_share` other than 100 is refused with
>   `422 validation_failed` naming `business_fee_share`, so a price you show your
>   customer is never one that cannot be booked. A prepaid quote that sends no
>   share is priced at 100, whatever your store's default is. So is a quote with
>   **no `payment_method`**, because the only delivery that can bind it is a
>   prepaid one: it is priced like a prepaid quote and refuses a share other than
>   100 the same way.
> * On a **create with no quote**, a share you send is forced to 100 and the
>   order is created.
> * A **create that binds a quote** needs a quote that was itself requested with
>   `payment_method: prepaid` or with no `payment_method`.
>
> Charge your customer for delivery in your own checkout if you want them to bear
> it.

## Whose balance a store spends

By default every store you create spends from the one balance above: you fund it
once and ship from all of your locations. That is the arrangement most
integrations want, and it is unchanged.

A store can instead own its money. Each store carries an `access_tier`:

| `access_tier` | Pays from | Its owner can sign in to |
| - | - | - |
| `api_only` (the default) | your balance | nothing |
| `wallet` | its own balance | the wallet pages: ledger, cash collected, withdrawals, top-ups |
| `full` | its own balance | the whole merchant console, dispatch included |

Where a store's money lives and who may sign in are one setting rather than two,
because neither half stands on its own: a store cannot be shown a balance it
does not own, and a store that owns one needs somewhere to see it.

Every store object also carries a read-only `billing`, either `"partner"` or
`"store"`, saying which arrangement that store is on. Read that rather than
mapping tiers to payers yourself.

A `full` store can also dispatch orders of its own from the console, and those
deliveries reach you like any other. See
[where a delivery came from](https://docs.listo.delivery/en/concepts/delivery-origin.md).

A restaurant that already runs on Listo with an account of its own reaches
`full` a different way: it is connected, never created. Its owner approves the
connection on a Listo page, and the store you get back already has
`access_tier: "full"` and `billing: "store"`, with the console, the balance and
the history it had before.
See [connect a restaurant that already uses Listo](https://docs.listo.delivery/en/guides/connect-existing-account.md).

On a store that owns its money, both sides of an order land on its balance: your
share of the fee is debited there when the delivery is created, and the cash a
courier collects is credited there when it arrives. Its earnings fund its own
deliveries, and its owner withdraws to its own bank.

Changing the tier takes effect on the **next** delivery. Orders already on the
road keep billing the account they started on, so nothing in flight can end up
with its debit on one balance and its credit on another.

A test store cannot own its money. Play money and real money never share an
account, so `access_tier` on a test store is always `api_only`, and setting
anything else is refused with `422 validation_failed`.

Reading one store's balance and its movements, and giving its owner a login, are
both in [balance and withdrawals](https://docs.listo.delivery/en/guides/balance-and-withdrawals.md).

## Charging your own markup

`markup_cents` on a store adds a fixed amount to every delivery fee for that
store, and credits that amount to your balance when the delivery arrives. It is
how you price your own service into the orders you dispatch, without running a
second billing system.

It is part of `fee_cents` like every other component, so `business_fee_share`
splits it exactly like the rest of the fee, and quotes include it: a quote you
bind charges the markup it was priced with, even if you changed the setting in
between.

Two consequences worth planning for:

* On a cash order the markup rides into what the courier collects, so it counts
  toward the MX\$1,000 cash limit.
* The credit posts when the delivery is **delivered**, not when it is created. A
  canceled or returned order collects nothing, refunds your fee share in full,
  and pays no markup, so there is no reversal to handle.

On a store that spends your balance, a markup is a visible wash: the same
balance pays the fee that includes it and is credited it back. Both movements
appear on the ledger rather than being quietly netted, because they are two
different facts about the order.

## What each payment method settles to

| | Who pays the goods | Who pays the customer's fee share | What reaches your balance |
| - | - | - | - |
| `prepaid` | Your customer, in your checkout | Nobody: `customer_fee_cents` is always 0 | Nothing in, your share out |
| `cash` | Your customer, in cash at the door | Your customer, in the same cash | The order value, once delivered |
| `card` | Your customer, on a Listo payment link | Your customer, on the same link | Nothing. Card settles to the bank of whoever is merchant of record |

Cash is the only method that pays *into* the balance. See
[cash at the door](https://docs.listo.delivery/en/concepts/cash-at-the-door.md).

## When a delivery does not happen

If a delivery ends `canceled`, `returned`, or `no_courier`, your share of the
fee is refunded to the balance, and so is any tip you sent with it. You are not
charged for a trip that did not deliver.

One thing can be deducted from that refund. A cancellation late enough that a
courier is already working on the order, or a return trip after a failed
dropoff, means a trip was driven anyway, and that trip is billed to you as a
separate debit: the delivery fee for each leg that was driven, less your own
store markup. A late cancellation is one leg. A return is two, the trip out and
the trip back. Cancel before a courier is engaged, or end at `no_courier`, and
nothing was driven: the refund is whole.

This changed on 29 August 2026. These charges used to be what the trip cost
Listo, so on the same orders they are larger now than they were.

The two are separate movements rather than one quietly reduced refund, so what
came back and what was charged are always told apart. Both are readable, in two
places: the charge is on the delivery itself, in `charges`, and both the refund
and the charge are rows on `GET /v1/ledger`.

A charge can also come back later. Some of these trips are costs Listo takes up
on your behalf after the fact, and when that succeeds the money returns as a
third movement, a `provider_charge_reversal` row on the ledger: the same amount,
credited in full, against the same order, weeks after the charge in some cases.
It is a new row rather than a rewrite of the old one, so the charge you already
billed to your own merchant stays exactly where it was and the credit is
something you can pass on in turn. Bill the charge when it lands. Do not hold an
order open in the hope of a reversal: not every charge is eligible for one, and
an eligible one can still be refused.

```json theme={null}
{
  "id": "dlv_7hK2mQ9xR4tV6bN1cZ8sLwYe",
  "status": "returned",
  "charges": [
    {
      "type": "return_fee",
      "amount_cents": 18560,
      "charged_at": "2026-08-01T18:41:03Z"
    }
  ]
}
```

`charges` is an array on every delivery and it is empty on almost all of them.
`type` is `cancellation_fee` or `return_fee`, naming what the charge was for,
and `amount_cents` is positive here: it is what you were charged. The same money
on the ledger is a row whose own `type` is `provider_charge`, carrying the
negative sign that says which way it moved on the account. The two `type` fields
are separate vocabularies, so do not go looking for `return_fee` on the ledger.

What the charge comes to depends on the trip and on how many legs were driven,
so read the number rather than assuming one, and `charged_at` is when it posted,
which is not when the delivery ended. Iterate the array rather than reaching for `charges[0]`: a charge object
has no id of its own, the delivery it hangs off is the handle for it, and that
delivery id is also how you line it up with the ledger.

> [!WARNING]
>
> **The charge can arrive after the delivery is over**
>
> The charge is settled once the cancellation or the return has been. When that
> happens with the status change itself, the delivery's final event already
> carries the charge. When it happens afterwards, `charges` fills in later and a
> `delivery.updated` fires for a delivery that already sent its final
> `delivery.status_changed`.
>
> So if you bill your own merchant the moment a delivery reaches its terminal
> status, the orders whose charge landed later are billed short. Handle that late
> `delivery.updated` too, or read the delivery back before you invoice. See
> [webhooks](https://docs.listo.delivery/en/guides/webhooks.md).

A refund you issue to your own customer on a delivery that *did* arrive does not
give you the delivery fee back. The trip ran and it was paid for.

## Reading the numbers back

Every delivery carries all of these figures, so nothing has to be recomputed:

```json theme={null}
{
  "order_value_cents": 19600,
  "fee_cents": 8004,
  "business_fee_cents": 0,
  "customer_fee_cents": 8004,
  "tip_cents": 0,
  "currency": "MXN",
  "payment": {
    "method": "cash",
    "status": "unpaid",
    "cash_to_collect_cents": 27604,
    "paid_at": null
  }
}
```

`fee_cents` is the total and nothing breaks it down further. How Listo divides
that total internally is not part of what you are billed, and it is not
published.

`tip_cents` sits beside those figures rather than inside them. It is on every
delivery and it is `0` rather than absent when there is no tip, so you read one
integer instead of testing for the field. What your balance was charged for an
order is `business_fee_cents + tip_cents`.

Two endpoints answer for the account behind those numbers. `GET /v1/balance` is
what it holds right now; `GET /v1/ledger` is how it got there, one row per
movement, the same rows the partner dashboard draws its ledger page from. When
you rebuild your books, rebuild them from the ledger rather than from the events
you received: the ledger is the record, and an event was only ever a
notification about one. See
[balance and withdrawals](https://docs.listo.delivery/en/guides/balance-and-withdrawals.md).

## Prices are never invented

If a delivery cannot be priced, it is refused. There is no fallback fee anywhere
in the system, so you will never be quoted a number that was made up because the
real one was unavailable. Depending on why, that refusal is
`503 provider_unavailable` (temporary, retry), `409 no_couriers_available`
(nobody near the trip is free right now, retry in a few minutes),
`422 out_of_service_area` (too far from that store), or
`422 address_undeliverable` (the address itself).


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