payments · tutorial · webhooks

Stripe Portal Truth: Cancel Should Mean Cancelled

Self-serve cancel plus instant access revoke: portal session, webhook transitions, expiry sweep. No zombie access, no support tickets. Inside.

Death as a skeleton leading an old man to his doctor, woodcut from Holbein's Dance of Death
Death as a skeleton leading an old man to his doctor, woodcut from Holbein's Dance of Death · Photo: Hans Holbein the Younger, CC0, via Wikimedia Commons

Cancelled customers who never leave

A user cancels on Stripe. Your database never hears about it, because the webhook failed once, silently, three months ago.

They keep exporting premium CSVs on a dead subscription while paying customers fund the free ride.

Or the reverse. A user cancels, access dies instantly mid-project, and support spends a week apologizing for an abruptness the cancel button never warned about.

Both failures share one cause. Cancel and access are two systems that never agreed.

Make them agree.

One portal.

One webhook chain.

One switch.

Cancel paths, ranked by leakage

Cancel path User effort Access revoked Leakage
"Email us to cancel" High, so they don't Manually, days late Weeks of free use
A dashboard button, no webhook One click Hope and a cron Until someone notices
Portal and webhook, no periodic check Self-serve Usually instant Strays on failures
Portal, webhook and periodic check Self-serve Instant, and backstopped Near zero

Half-built cancel flows leak. Three reasons.

Cancel at period end and cancel now confuse everyone. Users expect "stop charging me" to mean one thing. Stripe means two. Without clear copy and matching webhook handling, every cancel becomes a support conversation.

Failed webhooks strand access on. The cancellation event fails once, from a deploy overlap, a timeout or a bug, and nothing reconciles it later. Strays live forever.

No portal means support becomes billing. Every plan change, card update and invoice reprint lands in your inbox. A billing desk for twenty customers is the most expensive support queue in SaaS.

Self-serve cancel is not generosity. It is the cheapest support agent you will ever hire.

What to do

Open portal sessions. Never build billing UI.

A signed-in customer clicks one button and lands in Stripe's own portal, with a return link back to your billing page. Plan changes, card updates, invoice history and cancel buttons are Stripe's UI, wearing your branding.

Every custom billing screen is a liability that rots while the portal improves itself.

Switch access on webhook events, once.

When Stripe reports that a subscription changed or ended, map the status to the access switch. Active and trialing keep access. Anything else turns it off.

Record each event under a unique reference first, so a replay changes nothing. Orders accumulate as history and are never deleted.

Check Stripe's truth against yours now and then.

A monthly comparison of active subscriptions in Stripe against paid users in your dashboard catches strays. If you want it automated, add a daily job that fetches each paid user's subscription status and flags mismatches.

The cancel drill

Check Action Pass looks like
The portal opens Click manage billing A Stripe page with your branded return link
Cancel ends access Cancel in test mode Access turns off
The period-end term holds Cancel at period end Access until expiry, then off
A replay is safe Send the same event twice The second changes nothing
A stray is caught Break the webhook, compare Stripe to your dashboard You spot the mismatch

Drill with Stripe test clocks. They fast-forward a subscription through trial, active and canceled in minutes. Do it before real customers exist.

Rehearse quarterly. Cancel paths earn trust the way grant paths do.

The honest trade

Portal branding is Stripe's chrome around your logo. Less bespoke than a custom billing UI. And self-serve exit makes some would-be-stayers leave.

Treat both as wins.

Unmaintained UI beats pretty UI.

Customers who stay after an easy exit are retained.

Customers held by friction churn loudly later.

Know this first

BoringPush runs no nightly sweep. If a cancellation webhook is lost, a stray can keep access until you notice.

Compare Stripe to your dashboard each month.

Why BoringPush is the way to do this

Self-serve billing, without the screens.

Customers manage billing in Stripe's own portal. When a subscription ends, access turns off. Each event is recorded once.

No billing UI to build or maintain.

FAQ

Should cancel revoke access immediately or at period end?

Default to period end, which is what users expect from "cancel subscription". Offer immediate cancellation with explicit copy for the impatient. Match the words in your UI to what actually happens, because every mismatch becomes a support ticket.

How do win-back emails fit without being sleazy?

One email at cancel with a genuine thank-you and a one-line reason ask. One more at 30 days about what changed, if anything.

Then silence. The reasons feed your roadmap, while desperation sequences convert nobody.

Do lifetime buyers need a portal?

Receipts and invoice history, yes. Cancel flows, no.

Lifetime buyers have no subscription to manage, so the portal shows their payment record. BoringPush does not need separate code for the two buyer types.

How do disputes and chargebacks revoke access?

As webhook events like any other. A lost dispute or a refund turns access off if nothing else keeps it on, and the order records the change. Keep money state and access state in lockstep by sending every transition through the same handling.

Can users reactivate after canceling?

Through the portal before the period ends, or through a fresh checkout afterward. The history stays continuous on the same user. Returning customers are your best customers, so the path back should be shorter than the path out.

Keep reading

+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)

The Agent-First Shipping Kit

Command from your phone.

Built so autonomous AI agents build what you want without breaking what's already paying you.

$199

Get BoringPush

One-time payment · Lifetime updates · Unlimited projects.

Keep reading