> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywithsoap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# checkout.cancelled

> Event triggered when an accepted transfer is cancelled by the payment rail. Opt-in and processor-specific.

<Warning>
  `checkout.cancelled` is off by default. It will not be delivered until you enable it in Dashboard → Developers. See [Receiving Webhooks](/api-reference/api-v1/webhooks/setup) for instructions.
</Warning>

<Note>
  This event is **processor-specific**. It fires when a transfer that was already accepted for processing is cancelled by the rail — today that happens on bank-transfer rails, for **deposits as well as payouts**. Card rails do not emit it, so many accounts will never receive it. Ask Soap whether your rails emit it before you subscribe or write a handler, and branch on `data.type` / `charge.transaction_type` in your handler rather than assuming a payout.
</Note>

## Payload Structure

```typescript theme={null}
interface WebhookEvent {
  event_id: string;
  data: {
    id: string; // id of the checkout you originally created
    line_items: Array<{
      product_id: string;
      quantity: number;
      total_amount_cents: number;
      product_name: string;
      product_url: string | null;
      product_price_cents: number;
      sku: string | null; // null when the product was created without a sku
    }>;
    line_items_total_amount_cents: number | null;
    type: "deposit" | "withdrawal"; // the checkout type — not the event type below
    charge: {
      id: string;
      amount_cents: number;
      transaction_type: "credit" | "debit";
      status: string;
      from_status: string;
      failure_code: string | null;
      failure_message: string | null;
    };
    customer: {
      id: string;
    };
    subscription: {
      id: string;
      interval: "day" | "week" | "month" | "year";
      interval_count: number;
      line_items: Array<{
        product_id: string;
        sku: string | null; // null when the product was created without a sku
        product_name: string;
        product_url: string | null;
        quantity: number;
        price_cents: number;
        total_amount_cents: number;
      }>;
      line_items_total_amount_cents: number | null;
    } | null; // null for non-subscription checkouts
  };
  type: "checkout.cancelled";
}
```

## Example Response

```json theme={null}
{
  "event_id": "ev_tDaWu5aTVa2kbvDjGe55rxZpaMEmVFWB",
  "data": {
    "id": "chk_twijxXgVFofj9mdnvzF7vhbJSZEhfUpC",
    "line_items": [],
    "line_items_total_amount_cents": null,
    "type": "withdrawal",
    "charge": {
      "id": "ch_yRZcCGouimTgbz4thtrfbj2mh3ZT6vnz",
      "amount_cents": 2500,
      "transaction_type": "debit",
      "status": "cancelled",
      "from_status": "pending",
      "failure_code": null,
      "failure_message": null
    },
    "customer": {
      "id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870"
    },
    "subscription": null
  },
  "type": "checkout.cancelled"
}
```

## Updating Your Internal Ledger

`cancelled` is a terminal charge status. The charge typically moves from `pending` to `cancelled` — the transfer was accepted for processing and then cancelled before it settled. For a cancelled **deposit**, nothing was credited, so no ledger change is needed beyond marking the attempt closed; the charge's `failure_message` may say why.

For a cancelled **payout**, if you already debited the customer on [`checkout.hold`](/api-reference/api-v1/webhooks/checkout-hold), **credit them back here**, the same way you would for [`checkout.failed`](/api-reference/api-v1/webhooks/checkout-failed) with `from_status: "pending"`.


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