CANCEL FLOWSPADDLE

How to add a cancel flow to Paddle Billing

How cancellation works in Paddle Billing: the cancel API, scheduled changes, pause and resume, discounts, webhooks and where to add a retention step.

Published 6 min read

A cancel flow is the short step between “I want to cancel” and the cancellation itself: ask why, offer something that fits the reason, and cancel cleanly if the customer still wants to go. This guide explains how cancellation works in Paddle Billing, what Paddle already offers natively, and how to build your own retention step on top of its API.

It sticks to Paddle’s developer documentation: cancel a subscription, pause a subscription, resume a subscription, update a subscription, discounts, provisioning and webhooks, the customer portal and Cancellation Flows (all accessed November 2026). This is about Paddle Billing, not Paddle Classic, whose API is different.

Paddle is the merchant of record

One thing to keep in mind throughout: Paddle is the merchant of record for your sales. It sells to your customer, handles tax, and, per Paddle, handles billing support and chargebacks. That means the payment relationship is between the customer and Paddle. Your cancel flow should change subscriptions only through Paddle’s API or Paddle’s own tools, never by trying to stop payments some other way.

How cancellation works in Paddle Billing

Paddle gives you three places where a subscription can be cancelled.

1. The cancel API

You cancel with POST /subscriptions/{subscription_id}/cancel. The effective_from field decides when:

effective_from What happens
next_billing_period (default, also what an empty body does) Paddle adds a scheduled_change with action cancel. The subscription stays active until its next billing date, and next_billed_at becomes null
immediately The status changes to canceled right away and subscription.canceled fires

Paddle documents a few limits on the cancel page:

  • You cannot cancel or pause within 30 minutes of the next billing date.
  • A scheduled cancellation can be removed by updating the subscription with scheduled_change set to null. This is how you “undo” a cancellation before it takes effect.
  • A cancelled subscription cannot be reinstated. A returning customer needs a new subscription, which matters for win-back.
  • A paused subscription can only be cancelled with effective_from: immediately.

2. The customer portal

Paddle’s customer portal lets customers cancel and update payment details. Paddle’s docs say pausing is not supported in the portal, so a pause offer has to come from your app or from Paddle’s Cancellation Flows.

3. Paddle’s own Cancellation Flows

Paddle has a native feature for exactly this, part of Paddle Retain. You configure it under Retain › Cancellation Flows (setup guide). It asks for a cancellation reason and can offer a pause, a plan switch, contact with support, or a time-limited discount. Per Paddle’s January 2026 changelog, once a flow is set up it runs automatically when customers cancel in the customer portal or through cancellation links in Paddle’s subscription emails. In your own app you start it with Paddle.Retain.initCancellationFlow(), which returns a status such as retained, aborted or chose_to_cancel. A September 2026 changelog adds sandbox testing through the customer portal, while flows started with initCancellationFlow() still run only on live accounts.

To be clear: if all you need is a reason survey and a standard offer inside Paddle, this native feature may be enough, and Paddle lists it at no extra cost for Paddle Billing customers. The rest of this guide is for when you want your own flow, your own design, or offers that depend on data Paddle does not have.

The retention offers Paddle’s API supports

Pause

POST /subscriptions/{subscription_id}/pause pauses a subscription (guide). It takes effective_from (next_billing_period or immediately) and an optional resume_at date. A pause at the next billing period creates a scheduled change; the status becomes paused when it takes effect.

To bring a customer back early, POST /subscriptions/{subscription_id}/resume works only on paused subscriptions. The on_resume field decides billing: by default Paddle starts a new billing period and charges immediately; continue_existing_billing_period keeps the old period instead. Paddle also cancels past-due renewal transactions when a subscription is paused, to avoid charging twice for overlapping periods.

Discount

Create the discount once with POST /discounts. For a retention offer such as “50% off for 3 months”, set recur to true and maximum_recurring_intervals to the number of billing periods. Then apply it to the subscription with PATCH /subscriptions/{subscription_id}, passing a discount object with the discount’s ID and an effective_from of next_billing_period or immediately (update a subscription). Sending discount: null removes it. Paddle notes that renewals and mid-cycle changes do not count as new redemptions.

Plan change

A downgrade is also a subscription update: replace the items with the cheaper price. When you change items or the billing date, Paddle requires proration_billing_mode. Use the preview endpoint to show the customer what they will pay before confirming.

Building your own cancel flow on Paddle

  1. Put the cancel entry point in your app. Link “Cancel subscription” to your flow, not straight to the API call. Keep the customer portal available as well; it is Paddle’s own path and customers may use it.
  2. Ask one question: why. Use a short list of reasons plus “Other” with a free-text field. Store the answer with the subscription ID.
  3. Show one offer that matches the reason. “Too expensive” fits a discount or a cheaper plan. “Not using it right now” fits a pause with a resume_at date. “Missing a feature” or “Too complex” fits a conversation with support. Do not stack offers.
  4. Keep “Cancel now” visible on every step. The customer should be able to finish the cancellation at any point without accepting an offer. This is a matter of trust, and in several places, of law.
  5. Call Paddle for the outcome. Discount: PATCH the subscription with the discount. Pause: POST .../pause. Plan change: PATCH the items after a preview. Cancel: POST .../cancel with effective_from: next_billing_period, so the customer keeps what they paid for.
  6. Confirm what happens next. Tell the customer the date access ends or the date the pause ends. Read it from the subscription returned by Paddle rather than computing it yourself.
  7. Let them change their mind. Until the scheduled cancellation takes effect, a “Keep my subscription” button can clear scheduled_change.

Webhooks to listen to

Paddle’s provisioning guide recommends subscription.created and subscription.updated as the core events, because subscription.updated covers renewals, plan changes, pauses, resumes and cancellations. A few dedicated events are useful as clear signals:

Event When it fires
subscription.updated Any change, including a cancellation being scheduled
subscription.canceled The status becomes canceled: immediately, or on the billing date for a scheduled cancellation
subscription.past_due The subscription becomes past due after a failed renewal

Pauses and resumes also come through subscription.updated, with the status moving to or from paused; check Paddle’s webhooks reference for the dedicated events available in your API version.

Two details from Paddle’s docs: for a scheduled cancellation, keep access until the scheduled change’s effective date; and deduplicate on event_id and compare occurred_at, because events can arrive out of order. The subscription.canceled payload does not include management_urls.

After the cancellation: win-back

Because Paddle cannot reinstate a cancelled subscription, a win-back offer must lead to a new checkout. Keep the cancellation reason you collected, wait a reasonable time, and send an offer that answers that reason: a new feature for “missing features”, a lower price for “too expensive”. Send the customer to a checkout with the discount already applied.

Doing this with NoChurn

NoChurn reads your Paddle subscriptions and events and adds a cancel flow with reasons, offers (discount, pause, plan change) and a one-click cancel that stays visible at every step, either hosted or headless through the API. Accepted offers and cancellations are applied in Paddle, and Paddle stays the merchant of record: it keeps checkout, payments, payment recovery, tax and the customer portal. Disputes are handled by Paddle and shown in NoChurn read only. NoChurn also sends win-back emails at day 30, 60 and 90 based on the cancel reason, and is free under $300 MRR. See NoChurn + Paddle.

PROMPT

Read https://www.nochurn.sh/llms.txt,
then follow https://www.nochurn.sh/docs/quickstart/
to add NoChurn to this app. Use a test key
(nc_test_…) until I say we go live.

Stop leaking revenue.

  • Free until $300 MRR
  • No card needed
  • Live in 10 minutes
  • Never a cut of what we recover