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

# Connect Claude, Cursor or Codex

> Let your AI assistant quote, book, track and manage deliveries through your API key, with a confirmation step before anything moves money.

Listo runs an MCP server. Once your AI assistant is connected to it, you can ask
it in plain words to price a delivery, book it, follow it, look at your balance
or read your ledger, and it does so through your own API key. It is a second
door to the same API: every tool runs the matching `/v1/` endpoint, with the
same rules, errors and limits you already know from the rest of these docs.

The server lives at:

```text theme={null}
https://api.listo.delivery/mcp
```

It speaks MCP over Streamable HTTP, and it authenticates exactly like the API:
`Authorization: Bearer <your API key>`. Signing in with your browser (OAuth) is
not available yet.

> [!TIP]
>
> **Practice with a test key**
>
> Use a **test key** the first time. A test key only sees and changes test things:
> the courier is simulated, the money is play money and nothing real is booked
> (see [test mode](https://docs.listo.delivery/en/concepts/test-mode.md)). Switch to a live key when the
> assistant does what you expect. The first tool to call is `whoami`, which says
> which account the connection acts for and whether the key is test or live.

## Connect your client

Put your key in an environment variable first, so it never lands in a config
file you might commit:

```bash theme={null}
export LISTO_API_KEY="your key here"
```

### Claude Code

```bash theme={null}
claude mcp add --transport http listo https://api.listo.delivery/mcp --header 'Authorization: Bearer ${LISTO_API_KEY}'
```

Use single quotes exactly as shown. Claude Code expands `${LISTO_API_KEY}` each time it
connects, so the key itself is never written to its config file.

### Cursor

Add this to `mcp.json` (the project's `.cursor/mcp.json`, or the global one in
your home folder):

```json theme={null}
{
  "mcpServers": {
    "listo": {
      "url": "https://api.listo.delivery/mcp",
      "headers": {
        "Authorization": "Bearer ${env:LISTO_API_KEY}"
      }
    }
  }
}
```

Cursor reads `${env:LISTO_API_KEY}` from its own environment, so a key exported in
one terminal is not seen by a Cursor opened from the dock. Set the variable in your
shell profile or system environment, then restart Cursor.

### Codex

```bash theme={null}
codex mcp add listo --url https://api.listo.delivery/mcp --bearer-token-env-var LISTO_API_KEY
```

### ChatGPT

Sign-in for ChatGPT is coming. It needs the browser sign-in that this server
does not offer yet, so for now use one of the clients above.

## What the assistant can do

The tools, by what they are for. A tool marked **asks to confirm** moves or
charges money, or ends a paid service, and works in two steps (next section).

### Account and balance

| Tool | What it does |
| - | - |
| `whoami` | Which account the connection acts for, and whether the key is test or live. |
| `get_balance` | Your balance, what can be withdrawn today, and the part held in review. |
| `list_ledger` | Every movement on your balance, newest first. |
| `get_store_balance` | The balance one store spends from. |
| `list_store_ledger` | The movements on that store's balance. |

### Stores

| Tool | What it does |
| - | - |
| `list_stores` | Your stores, newest first; find one by your own `external_id`. |
| `get_store` | One store: address, pickup notes, access tier and plan. |
| `create_store` (**asks to confirm**) | Registers a pickup location. On a live key it can start the store's plan and charge the first month. |
| `update_store` | Changes a store. Bookings already made are not affected. |
| `invite_store_owner` | Emails the person who runs a store a link to choose their own password. |
| `start_card_onboarding` | Starts card payments setup for a store, or for the company, and returns a one-time link for whoever answers for the business. |
| `get_card_status` | Whether a store or the company can take card payments yet, and what is outstanding. |
| `connect_existing_restaurant` | Starts the flow that connects a restaurant that already uses Listo, and returns the link for its owner (live keys only). |
| `complete_connection` | Exchanges the code the owner's approval returns for the connected store. |

### Deliveries

| Tool | What it does |
| - | - |
| `quote_delivery` | Prices a delivery from one of your stores and holds that price for a short time. Books nothing. |
| `create_delivery` (**asks to confirm**) | Books a courier at the price of a quote. |
| `list_deliveries` | Your deliveries, newest first, with filters. |
| `get_delivery` | One delivery: status, courier, payment, fee and tracking link. |
| `update_delivery` | Moves a scheduled pickup, or corrects the drop-off note for the courier. |
| `cancel_delivery` (**asks to confirm**) | Cancels a delivery that has not been delivered. Once a courier is assigned this can cost money. |
| `retry_delivery` (**asks to confirm**) | Looks for a courier again for a delivery nobody took. Priced and charged again. |
| `refund_delivery` (**asks to confirm**) | Gives a customer money back on a card-paid delivery, in full or in part. |

### Withdrawals

| Tool | What it does |
| - | - |
| `request_withdrawal` (**asks to confirm**) | Requests a transfer from your balance to your registered bank account. |
| `list_withdrawals` | Your withdrawal requests, newest first. |
| `get_withdrawal` | One withdrawal: amount, status and, once paid, the transfer's tracking key. |

### Plans

| Tool | What it does |
| - | - |
| `cancel_store_plan` (**asks to confirm**) | Cancels a store's plan. It keeps serving until the end of the period already paid. |
| `undo_plan_cancellation` (**asks to confirm**) | Reverses that cancellation before it takes effect. |
| `reactivate_store_plan` (**asks to confirm**) | Restarts a store's plan that has ended, charging the first month now. |

The three plan tools work on live keys only. What a plan is and when it is
charged is in [plan and billing](https://docs.listo.delivery/en/guides/plan-and-billing.md).

### Logs, events and webhooks

| Tool | What it does |
| - | - |
| `search_api_logs` | Your recent API calls, newest first, narrowed by status, endpoint, request\_id or time. |
| `get_api_log` | One call, with the request body you sent and the response body you got back. |
| `list_events` | The events Listo emitted for you, whether or not your endpoint received them. |
| `get_event` | One event, exactly as your endpoint is sent it. |
| `list_webhook_deliveries` | Each attempt to deliver an event to your endpoint: what it answered, how long it took, and whether it counted as a success. |
| `resend_event` | Sends one event to your endpoint once more. It acts at once and asks no confirmation, because it moves no money. |
| `send_test_webhook` | Sends a synthetic event of any published type to your webhook URL. It acts at once and asks no confirmation. |

The two that send act the moment they are called, with the same limits as the API
endpoints behind them. The attempt they cause is read with `list_webhook_deliveries`.
How to use all of these to find out why an integration does not work is in
[debugging your integration](https://docs.listo.delivery/en/guides/debugging.md#debug-with-your-ai-assistant).

### Feedback

| Tool | What it does |
| - | - |
| `submit_feedback` | Tells Listo what the assistant could not do, or what was missing or confusing, so the tools get better. A few submissions per hour. |

Lists are 50 per page, like the API: when an answer says there is more, the
assistant passes the `next` cursor back to read the next page.

## Nothing moves money until you say so

Every tool marked **asks to confirm** works in two steps, and the assistant is
told to stop between them and show you what is about to happen:

1. **The preview.** The assistant calls the tool with the details. Nothing
   happens. It gets back what *would* happen (for a booking: the price, the
   store, the drop-off) and a `confirmation_token`, and it shows you.
2. **The confirmation.** Only after you approve, it calls the tool again with
   exactly the same arguments plus `confirm: true` and the token. That is the
   moment money moves.

What makes this safe:

* **Booking always uses a quote.** `create_delivery` requires the `quote_id`
  from `quote_delivery`, so the price you were shown is the price booked. If the
  quote has expired or was already used, the booking is refused and the
  assistant quotes again.
* **A token works once and for ten minutes.** It belongs to your key, to that
  tool and to exactly those arguments: change the amount or the delivery and the
  token is refused, and it is not used up by the mistake. A token nobody used is
  refused as `confirmation_expired` once the ten minutes pass: ask for a new
  preview.
* **A repeated confirm never acts twice.** Confirming the same token again, for
  instance because the assistant retried after a dropped connection, returns the
  first result and books, cancels or withdraws nothing a second time. That
  replay holds for 24 hours after the token expired. Later than that the record is
  gone and a confirm answers `confirmation_not_found`: have the assistant read the
  resource first (for example with `get_delivery`) before it previews again.
* **A read-only key gets no preview.** With a read-only key, a tool that asks to
  confirm is refused at the first step with `read_only_key` and no token is
  issued, because the confirmation could only fail. Sending feedback with
  `submit_feedback` still works.

> [!WARNING]
>
> **Keep your client's own approval prompt on**
>
> The two steps are Listo's safeguard. Your client has its own: Claude Code,
> Cursor and Codex can each ask you before running a tool. Leave that on for the
> tools that ask to confirm, at least, so a person sees every call that can move
> money, not only the preview.

## Limits and logs

* A tool call is one API request against your key's limits, the same ones as
  anywhere else (see [go live](https://docs.listo.delivery/en/guides/go-live.md#rate-limits)). Over a
  limit the assistant gets `rate_limited`. Any error that asks the assistant to wait
  (`rate_limited`, `resend_limit_reached` and `test_webhook_limit_reached`) carries
  `retry_after_seconds`, the number of seconds to wait before it tries the same call again.
* Every tool call appears in your API logs like any `/v1/` request, except
  `submit_feedback`, which calls no `/v1/` route, and a preview a read-only key
  was refused, which never reaches one.
* Errors are the API's own: the assistant sees the same `code` and `retryable`
  you would, and branches on them the same way. Each error also carries a
  `doc_url` and a `request_id`, which is the `X-Request-Id` of that `/mcp`
  response.

## When the tools are not enough

If the assistant needs something no tool offers, it can say so with
`submit_feedback`. That is how we learn what to add next.


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