> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).
>
> To search these docs, send a `GET` request to `https://paddle-docs-retrieval.kapa-paddle.workers.dev/?q=<question>` with a URL-encoded question. No authentication needed. It returns a JSON array of `{content, source_url}`, most relevant first.

# Cancellation flow sessions reports

Generate detailed reports about your cancellation flow sessions, including cancellation reasons, feedback, salvage attempts and offers, and how each session was resolved.

---

Cancellation flow sessions reports contain information about each time a customer went through one of your [Cancellation Flows](https://developer.paddle.com/concepts/retain/cancellation-flows-surveys.md), including the reason they gave for canceling, their feedback, what they decided on the salvage attempts and offers they saw, and how the session ended.

Use them to understand why customers cancel and how well your flows salvage subscriptions.

{% callout type="info" %}
Cancellation flow sessions reports are available if the report is enabled on your account. They include sessions from the flows you manage under **Paddle > Retain > Cancellation Flows** only.
{% /callout %}

## When to use

- **Understand why customers cancel**  
  See the cancellation reasons, satisfaction insights, and free-text feedback customers give, with the subscription and products each session relates to.
- **Measure how well your flows salvage subscriptions**  
  Compare how many sessions were salvaged, failed to salvage, or were abandoned, which salvage attempts customers accepted, and how many accepted a salvage offer.
- **Automate reporting workflows**  
  Generate reports via API to feed cancellation data into your own dashboards and business intelligence tools.

## Report filters

When generating cancellation flow sessions reports, you can filter by:

| Field | Description | Use case |
|-------|-------------|------------|
| `cancellation_flow_session_created_at` | Filter by the date range when sessions were created. Pass an RFC 3339 datetime string with a `gte` or `lt` operator, and combine two filters to scope to a specific range. If you don't pass a `gte` filter, the report includes sessions created in the month before it was generated. | Reporting on sessions for a specific period. |
| `cancellation_flow_id` | Filter by cancellation flow. Pass one or more cancellation flow IDs, prefixed with `cfl_`. To find a flow's ID, generate a report without this filter and read it from the `cancellation_flow_id` column. | Reporting on specific cancellation flows. |
| `cancellation_flow_session_resolution` | Filter by how sessions ended. Pass one or more of `salvaged`, `failed_to_salvage`, and `abandoned`. | Building a list of customers who canceled through a flow, or reviewing the sessions where a salvage attempt or offer worked. |

### Which sessions are included

A session starts when a customer begins a cancellation flow. It appears in the report in the next daily update after it ends, with one of these resolutions:

- `salvaged`: the customer accepted a salvage attempt or a salvage offer and kept their subscription.
- `failed_to_salvage`: the customer canceled their subscription. This includes cases where they accepted a salvage attempt, such as contacting support, and still went on to cancel. The cancellation can be scheduled for the end of the billing period, so the subscription may still be `active` or `trialing`. A customer who leaves the flow and then cancels another way shows as `abandoned`, not `failed_to_salvage`.
- `abandoned`: the customer closed the flow, or stopped using it until the session timed out, before it ended in a salvage or a cancellation. Once a one-click cancellation is scheduled, the session can't end as `abandoned`.

Sessions that are still in progress aren't included. A session that timed out has no `cancellation_flow_session_completed_at`, and the customer can still come back to it. If they finish it, later reports show its new resolution.

### How session details are recorded

A cancellation flow can try to keep a customer in two ways:

- **Salvage attempt**: an option to stay without a discount, such as pausing the subscription, switching plans, or contacting your support team. The flow picks one based on the customer's survey answers.
- **Salvage offer**: a temporary discount to stay. If you turn salvage offers on, the flow can present one when the customer doesn't accept the attempt.

`cancellation_flow_session_salvage_offer_discount_percentage` and `cancellation_flow_session_salvage_offer_discount_max_recurring_intervals` are set when the session starts, so they can have values even when `cancellation_flow_session_is_salvage_offer_shown` is `false`.

In regions that require one-click cancellation, customers can cancel at any point in the flow. Paddle can schedule the cancellation and keep the flow open, so the customer can still accept a salvage attempt or offer afterward. Those sessions have `cancellation_flow_session_is_one_click_cancellation` set to `true`.

When the flow can't stay open, such as when a subscription renews within 24 hours, a one-click cancellation ends the session straight away. A session with a scheduled one-click cancellation doesn't time out, so if the customer leaves without finishing the flow, it can stay in progress and isn't in the report.

`product_id_list`, `price_id_list`, `subscription_billing_interval`, `subscription_billing_frequency`, and `customer_country_code` describe the subscription as it was when the session started. If a customer switches plans as part of the flow, the report still shows the original plan they tried to cancel. `product_name_list` is the exception: it shows each product's current name.

{% callout type="info" %}
Cancellation flow sessions reports are updated daily. `customer_email` holds each customer's current email address, so it may differ from the one they had when they went through the flow.
{% /callout %}

## Report columns

Each row in the report is one cancellation flow session. Columns cover the session, the flow, what the customer said and decided, and the subscription they tried to cancel:

- **Session**: when the session started and ended, and how it was resolved, like `cancellation_flow_session_created_at` and `cancellation_flow_session_resolution`.
- **Flow**: which flow the customer went through and where, like `cancellation_flow_name` and `cancellation_flow_session_channel`.
- **Survey answers**: what the customer told you, like `cancellation_flow_session_cancel_reason` and `cancellation_flow_session_additional_feedback`.
- **Salvage attempts and offers**: what the flow presented and what the customer decided, like `cancellation_flow_session_salvage_attempt` and `cancellation_flow_session_salvage_offer_decision`.
- **Customer**: who the customer is, like `customer_id` and `customer_country_code`.
- **Subscription**: the subscription as it was when the session started, like `subscription_id` and `product_id_list`.

Column headings on cancellation flow sessions reports mirror fields in [the Paddle API](https://developer.paddle.com/api-reference.md). Data is provided in the following columns:

```yaml
title: Cancellation flow sessions report
type: object
properties:
  cancellation_flow_session_id:
    type: string
    pattern: ^cflses_[a-z\d]{26}$
    description: Unique Paddle ID for this cancellation flow session, prefixed with `cflses_`.
    title: Cancellation flow session ID
    examples:
      - cflses_01jz8m2q4k7vx3t9bnc6rhd5yw
  cancellation_flow_session_created_at:
    type: string
    format: date-time
    description: RFC 3339 datetime string of when the customer started this session. The `cancellation_flow_session_created_at` filter matches on this column.
    title: Created at
    examples:
      - "2026-11-03T14:21:12.340Z"
  cancellation_flow_session_updated_at:
    type: string
    format: date-time
    description: RFC 3339 datetime string of when this session last changed status. It doesn't change when other details are added to a session, such as feedback, or when a session is abandoned because it timed out.
    title: Updated at
    examples:
      - "2026-11-03T14:23:40.112Z"
  cancellation_flow_session_completed_at:
    type:
      - string
      - "null"
    format: date-time
    description: RFC 3339 datetime string of when this session was completed. `null` if the session timed out.
    title: Completed at
    examples:
      - "2026-11-03T14:23:40.112Z"
  cancellation_flow_session_resolution:
    type: string
    enum:
      - salvaged
      - failed_to_salvage
      - abandoned
    description: How this session ended. The `cancellation_flow_session_resolution` filter takes the same values.
    x-enum-descriptions:
      salvaged:
        description: The customer accepted a salvage attempt or a salvage offer and kept their subscription.
      failed_to_salvage:
        description: The customer canceled their subscription. This includes customers who accepted a salvage attempt, such as contacting support, and still went on to cancel. The cancellation can be scheduled for the end of the billing period, so the subscription may still be `active` or `trialing`.
      abandoned:
        description: The customer closed the flow, or stopped using it until the session timed out, before it ended in a salvage or a cancellation.
  cancellation_flow_id:
    type: string
    pattern: ^cfl_[a-z\d]{26}$
    description: Paddle ID of the cancellation flow that this session ran through, prefixed with `cfl_`. The `cancellation_flow_id` filter matches on this column.
    title: Cancellation flow ID
    examples:
      - cfl_01jx4d7h2p9rk5wm3sbt8yq6nc
  cancellation_flow_name:
    type:
      - string
      - "null"
    description: Name of the cancellation flow that this session ran through. This is the flow's current name.
    title: Cancellation flow name
  cancellation_flow_session_channel:
    type: string
    enum:
      - portal
      - in_app
    description: Where the customer went through the cancellation flow.
    x-enum-descriptions:
      portal:
        description: The customer went through the flow in the customer portal.
      in_app:
        description: The customer went through the flow outside the customer portal, such as in your app or website.
  cancellation_flow_session_is_one_click_cancellation:
    type: boolean
    description: Whether the customer canceled using the one-click link while the flow stayed open to offer salvage attempts and offers. Stays `true` if they accepted and the session ended `salvaged`. `false` if the flow had no one-click link, or if one-click cancellation closed the flow straight away.
  cancellation_flow_session_cancel_reason:
    type:
      - string
      - "null"
    description: Text of the cancellation reason that the customer chose, as set up in your cancellation flow. `null` if the customer didn't choose a reason.
    examples:
      - Too expensive
  cancellation_flow_session_satisfaction_insight:
    type:
      - string
      - "null"
    description: Text of the satisfaction insight that the customer chose, as set up in your cancellation flow. `null` if the customer didn't choose one.
    examples:
      - Easy to use
  cancellation_flow_session_additional_feedback:
    type:
      - string
      - "null"
    description: Free-text feedback that the customer entered. `null` if the customer didn't enter any feedback.
  cancellation_flow_session_salvage_attempt:
    type:
      - string
      - "null"
    enum:
      - pause_plan
      - switch_plan
      - contact_support
      - calendar_invite
      - none
      - null
    description: Salvage attempt that the cancellation flow presented to the customer. Salvage attempts are options to stay without a discount, such as pausing a subscription. Salvage offers are temporary discounts to stay, recorded in `cancellation_flow_session_salvage_offer_decision`. `null` if the session ended before the customer answered the survey.
    x-enum-descriptions:
      pause_plan:
        description: The customer was offered to pause their subscription.
      switch_plan:
        description: The customer was offered to switch to a different plan.
      contact_support:
        description: The customer was offered to contact your support team.
      calendar_invite:
        description: The customer was offered a link to book a meeting with your team.
      none:
        description: The flow didn't present a salvage attempt, either because the customer's survey answers don't map to one or because the mapped attempt isn't available for this customer.
  cancellation_flow_session_salvage_attempt_decision:
    type:
      - string
      - "null"
    enum:
      - accepted
      - rejected
      - null
    description: Whether the customer accepted or rejected the salvage attempt. `null` if the flow didn't present a salvage attempt, or if the customer left the flow without deciding.
  cancellation_flow_session_is_salvage_offer_shown:
    type: boolean
    description: Whether the customer made a decision on a salvage offer. A customer who saw an offer and closed the flow without accepting or rejecting it counts as `false`.
  cancellation_flow_session_salvage_offer_decision:
    type:
      - string
      - "null"
    enum:
      - accepted
      - rejected
      - null
    description: Whether the customer accepted or rejected the salvage offer, which is a temporary discount to stay. `null` if the customer didn't make a decision on a salvage offer.
  cancellation_flow_session_salvage_offer_discount_percentage:
    type:
      - integer
      - "null"
    description: Percentage discount that the flow would offer this customer as a salvage offer, such as `20` for 20% off. `null` if the customer wasn't eligible for a salvage offer, if no discount in the flow matched the subscription's billing cycle, or for sessions created before this column was added.
  cancellation_flow_session_salvage_offer_discount_max_recurring_intervals:
    type:
      - integer
      - "null"
    description: How many billing cycles the offered discount lasts. `null` whenever `cancellation_flow_session_salvage_offer_discount_percentage` is `null`. The two are always set or `null` together.
  customer_id:
    type: string
    pattern: ^ctm_[a-z\d]{26}$
    description: Paddle ID of the customer who went through the cancellation flow, prefixed with `ctm_`.
    title: Customer ID
    examples:
      - ctm_01grnn4zta5a1mf02jjze7y2ys
  customer_email:
    type:
      - string
      - "null"
    description: Current email address of the customer who went through the cancellation flow. It may differ from the address they had when the session started.
  customer_country_code:
    type:
      - string
      - "null"
    description: Two-letter ISO 3166-1 alpha-2 country code of the subscription's billing address, recorded when the session started. `null` if Paddle couldn't look up the address at the time, or for sessions created before this column was added.
    examples:
      - US
  subscription_id:
    type: string
    pattern: ^sub_[a-z\d]{26}$
    description: Paddle ID of the subscription that the customer tried to cancel, prefixed with `sub_`.
    title: Subscription ID
    examples:
      - sub_01h04vsc0qhwtsbsxh3422wjs4
  subscription_billing_interval:
    type:
      - string
      - "null"
    enum:
      - day
      - week
      - month
      - year
    description: Unit of the subscription's billing cycle, recorded when the session started. Read it together with `subscription_billing_frequency`, which says how many of these units each cycle spans. `null` for subscriptions that only have one-time prices or that have recurring prices on different billing cycles, or for sessions created before this column was added.
    x-enum-descriptions:
      day:
        description: Billing cycles are measured in days.
      week:
        description: Billing cycles are measured in weeks.
      month:
        description: Billing cycles are measured in months.
      year:
        description: Billing cycles are measured in years.
  subscription_billing_frequency:
    type:
      - integer
      - "null"
    description: How many `subscription_billing_interval` units each billing cycle of the subscription spans, recorded when the session started. With an interval of `month`, `1` is monthly and `3` is quarterly. `null` if `subscription_billing_interval` is `null`. The two are always null together.
  product_id_list:
    type: array
    items:
      type: string
      pattern: ^pro_[a-z\d]{26}$
    description: Array of IDs of the products on the subscription, prefixed with `pro_`, recorded when the session started. `[]` for sessions created before this column was added.
  product_name_list:
    type: array
    items:
      type: string
    description: Names of the products in `product_id_list`, listed in the same order. These are the products' current names, so a renamed product shows its new name, including for earlier sessions. Holds an empty string for a product with no name.
  price_id_list:
    type: array
    items:
      type: string
      pattern: ^pri_[a-z\d]{26}$
    description: Array of IDs of the prices on the subscription, prefixed with `pri_`, recorded when the session started. `[]` for sessions created before this column was added.
  price_name_list:
    type: array
    items:
      type: string
    description: Names of the prices in `price_id_list`, listed in the same order and recorded when the session started. Holds an empty string for a price with no name.
```