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

# Fetch a withdrawal

> Fetches one withdrawal by its `wd_` id, which is how you check on one
that has not resolved yet without waiting for its webhook.

Once it is `paid`, `clave_de_rastreo` carries the SPEI tracking key your
bank uses to find the deposit, so this is also the endpoint to reconcile
a payout from if you would rather poll than handle the webhook.




## OpenAPI

````yaml /openapi/en.yaml get /v1/withdrawals/{id}
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/withdrawals/{id}:
    get:
      tags:
        - Withdrawals
      summary: Fetch a withdrawal
      description: |
        Fetches one withdrawal by its `wd_` id, which is how you check on one
        that has not resolved yet without waiting for its webhook.

        Once it is `paid`, `clave_de_rastreo` carries the SPEI tracking key your
        bank uses to find the deposit, so this is also the endpoint to reconcile
        a payout from if you would rather poll than handle the webhook.
      operationId: getWithdrawal
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          example: wd_2xN6bK9mR4tQ7vC1sZ8pLwYe
      responses:
        '200':
          description: The request succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Withdrawal'
              example:
                id: wd_2xN6bK9mR4tQ7vC1sZ8pLwYe
                amount_cents: 250000
                currency: MXN
                status: paid
                requested_at: '2026-07-30T18:30:00Z'
                resolved_at: '2026-06-09T15:00:00Z'
                test: false
                clave_de_rastreo: MBAN01002608120001234567
                fee_cents: 0
                kind: standard
                due_at: null
        '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:
    Withdrawal:
      type: object
      description: A request to move money out of your balance to your bank account.
      properties:
        id:
          type: string
          description: The withdrawal id, `wd_` prefixed.
          example: wd_2xN6bK9mR4tQ7vC1sZ8pLwYe
        amount_cents:
          type: integer
          description: |
            What your bank receives. On a `same_day` withdrawal the fee is a
            SECOND debit rather than a deduction, so this figure is what lands
            either way and `fee_cents` is what your balance loses on top of it.
        fee_cents:
          type: integer
          description: |
            What the withdrawal cost, IVA included. Always `0` on a `standard`
            withdrawal. Always present.
        currency:
          type: string
          enum:
            - MXN
        kind:
          type: string
          enum:
            - standard
            - same_day
          description: |
            `standard` is the free path: your released balance only, sent in 1
            to 3 business days. `same_day` costs `fee_cents`, can reach cash
            still on hold, and is sent the same day within the hours in
            `POST /v1/withdrawals`.
        status:
          type: string
          enum:
            - pending
            - paid
            - failed
          description: |
            `pending` until a human settles it. The move to `paid` or `failed`
            is what `withdrawal.updated` announces.
        requested_at:
          type:
            - string
            - 'null'
          format: date-time
        due_at:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            When a `same_day` withdrawal is due to have been sent, stamped when
            you requested it and never recalculated afterwards. Null on every
            `standard` withdrawal: the free path promises a range of business
            days rather than an instant.
        resolved_at:
          type:
            - string
            - 'null'
          format: date-time
          description: Null while still pending.
        clave_de_rastreo:
          type:
            - string
            - 'null'
          nullable: true
          description: |
            The SPEI tracking key for the transfer: the identifier your own bank
            uses to locate the deposit. This is what you reconcile a payout
            against a bank statement with, and it is the same key you see in the
            dashboard for this withdrawal.

            Always present, null until the transfer is sent. It stays null
            forever on a `failed` withdrawal, because no transfer happened.
          example: MBAN01002608120001234567
        test:
          type: boolean
      required:
        - id
        - amount_cents
        - fee_cents
        - currency
        - kind
        - status
        - requested_at
        - due_at
        - resolved_at
        - clave_de_rastreo
        - test
    ErrorResponse:
      type: object
      description: The body of every 4xx and 5xx answer on this API.
      properties:
        error:
          $ref: '#/components/schemas/Error'
      required:
        - error
    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.