Skip to Content
Supported subscriptionsOverview

Supported subscriptions

Reference page. Use this to look up which subscription shapes Unchurn handles automatically, which ones route to a manual cancellation request, and why.

For the rationale behind the rules, see Unusual subscriptions. This page lists the rules without re-explaining them.

What gets checked

Every cancel session is checked when the flow opens and again when we make the change to Stripe. The result is one of three states.

StateWhat happensCustomer sees
Eligible for one or more retention offersWidget renders the eligible offers in waterfall order. Customer picks one (or declines and cancels).Discount, pause, plan-switch, trial extension tiles — only the ones that are safe for this sub.
Not eligible for offers, eligible for automated cancelWidget skips the offer waterfall and shows the cancel confirmation.”Subscription will end on <date>.”
Not eligible for automated cancelWidget records a manual cancellation request, notifies you, and shows an honest confirmation.”Your cancellation request has been received.” Never “your subscription has been canceled.”

The third state is the one most cancel-flow tools get wrong. See Manual cancellation request below.

Where to look

  • Per-offer eligibility — one table per offer (cancel, discount, pause, plan-switch, trial extension). Each table lists the conditions a subscription must satisfy.
  • Blocked subscription shapes — the full list of subscription shapes blocked from automated cancel, with the Stripe-API reason for each.

Manual cancellation request

When a subscription shape isn’t safe for automated cancel, the cancel button doesn’t call Stripe. Instead we record a manual cancellation request in a single database transaction.

What the customer sees

  1. The cancel button in the widget.
  2. A confirmation screen: “Your cancellation request has been received.” The screen may include your support_url as an optional contact link.
  3. A confirmation email (sent immediately, retried in the background until delivered).

The screen never says “your subscription is canceled” for blocked shapes. The copy stays honest about what actually happened.

What you receive

  • A merchant dashboard task with the subscription ID, customer ID, the reason the automated path was blocked, and the timestamp.
  • An audit timestamp (merchant_manual_cancellation_notified_at) stamped in the same transaction as the request, queryable via your dashboard. Outbound webhook delivery to your server is on the roadmap.
  • The session row records outcome='manual_cancellation_requested', clicked_to_cancel=true, and the deterministic manual_cancellation_request_id.

Double-clicks and retries collapse to one request via ON CONFLICT (id) DO NOTHING on the deterministic id.

What does not happen

  • No subscriptions.update call to Stripe.
  • No standard onComplete event.
  • No cancel_scheduled outcome.
  • The session is not counted as “saved” or “compliance-success-automated” in your analytics.

You complete the Stripe-side cancellation manually when you’re ready. Until then, the customer’s intent is captured and dated.

How this satisfies FTC Click-to-Cancel

The FTC’s click-to-cancel principle requires that cancellation be processed immediately upon request — not that access be revoked immediately. The customer paid for the period; cutting access mid-period would harm the customer experience and is not what the rules require.

PathWhat “immediate” means
Automated cancelsubscriptions.update({ cancel_at_period_end: true }) is called the moment the customer clicks. Stripe records the cancellation immediately. The customer keeps access through the paid period.
Manual cancellation requestThe request is recorded in the database in the same transaction as the merchant notification and customer-confirmation outbox, the moment the customer clicks. The merchant completes the Stripe-side cancellation within their legal SLA.

Both paths are one click from the cancel-flow open. No surveys, no offers, and no “are you sure” interstitials sit between the customer and the cancel action when direct cancellation access is rendered.

For blocked shapes the position is received, not completed — manual cancellation requests are tracked separately from automated cancels in your analytics.

Stripe-side primitives

The five offers map to these Stripe calls. Full per-offer eligibility on the per-offer page.

OfferStripe callCadenceStripe docs
Cancelsubscriptions.update({ cancel_at_period_end: true })Anysubscriptions overview 
Discountcoupons.create then subscriptions.update({ discounts: [{ coupon }] })Anycoupons 
Pausesubscriptions.update({ pause_collection: { behavior: 'void', resumes_at } })Monthly onlypause-payment 
Plan-switchsubscriptions.update({ items: [{ id, price, quantity }], proration_behavior: 'none' })Monthly only, downgrades onlybilling-cycle 
Trial extensionsubscriptions.update({ trial_end, proration_behavior: 'none' })Trialing subs onlybilling-cycle 

The pause call uses the collection-level pause_collection, not Stripe’s first-class status='paused' API. The two are separate models with separate resume paths.

Roadmap

Annual pause, broader plan-switch transitions, discount stacking, and schedule-backed cancel are on the roadmap. No dates. The supported set today is what the per-offer page and blocked shapes page describe.

Last updated on