Knowledge > Runbooks > Customer Ops > Cancel Subscription
Cancel a Church Subscription
Handle a subscription cancellation, whether triggered automatically via Stripe webhook or executed manually at a church's request.
Prerequisites
- Stripe CLI logged in (test mode by default; live mode needs
--api-key $STRIPE_LIVE_SECRET_KEY) - Supabase access
- The church's Stripe subscription ID (
sub_...) or customer ID (cus_...)
Automated Flow (what should happen)
When a church cancels via the Stripe customer portal or the subscription expires:
- Stripe fires
customer.subscription.deleted(immediate cancel) orcustomer.subscription.updated(cancel at period end) - Webhook handler updates
premium_churchesto reset plan/tier - Church loses premium feature access at the appropriate time
Steps — Manual Cancellation at Church Request
-
Find the church's subscription ID
stripe customers list --email "[church-email]"Note the
cus_ID, then:stripe subscriptions list --customer cus_xxxxxxxxxxxxNote the
sub_ID andcurrent_period_enddate (Unix timestamp — tells you when access should end). -
Cancel the subscription in Stripe
Cancel at period end (recommended — church retains access until they've paid for):
stripe subscriptions update sub_xxxxxxxxxxxx --cancel-at-period-end=trueCancel immediately (use only if church requests immediate cancellation or for refund):
stripe subscriptions cancel sub_xxxxxxxxxxxxFor live mode, append:
--api-key $STRIPE_LIVE_SECRET_KEY -
Verify the Stripe webhook fired (for immediate cancellation)
stripe events list --limit 5Look for
customer.subscription.deletedwithstatus: delivered. -
Verify
premium_churcheswas updatedSELECT church_id, plan, tier, stripe_subscription_id, updated_atFROM premium_churchesWHERE stripe_subscription_id = 'sub_xxxxxxxxxxxx';After immediate cancellation:
planshould be'free'(or the row removed, depending on webhook handler implementation). After cancel-at-period-end, the row remains active until the period ends. -
If webhook did not fire — update manually
UPDATE premium_churchesSET plan = 'free',tier = NULL,stripe_subscription_id = NULL,updated_at = now()WHERE stripe_subscription_id = 'sub_xxxxxxxxxxxx';Confirm with founder before running this in live mode.
-
Send a cancellation confirmation email to the church (if not automated via Stripe/Resend)
Cancel-at-Period-End Behavior
When cancel-at-period-end=true:
- Stripe does NOT immediately fire
customer.subscription.deleted - The subscription stays active until
current_period_end - Stripe fires
customer.subscription.deletedat that date - The church retains full access until then
If you need to verify what date their access ends:
stripe subscriptions retrieve sub_xxxxxxxxxxxx
Look at current_period_end (convert Unix timestamp to date).
Refund
If the church is also requesting a refund, see refund.md after completing cancellation.
Verification
After cancellation:
- Church cannot access premium features at churchwiseai.com/admin (if immediately cancelled)
- Stripe subscription shows
status: canceled premium_churchesrow reflects the correct state
See Also
- refund.md — process a refund after cancellation
- onboard-new-church.md — if they resubscribe later
C:\dev\PRICING.md— plan definitions and cancellation policy referencesC:\dev\knowledge\data\policies.yaml— cancellation and refund policies