Chapter 13: Cancellations, Pauses, and Winback
Handling cancellations from scratch means writing code for user-initiated cancellation, developer-initiated cancellation via API, system cancellation, pause states, restoring canceled subscriptions, resubscribing, subscription deferrals, and revocations.
Most of these are passive events your app observes rather than initiates. RevenueCat reflects them all in CustomerInfo. The code you write to handle them is small.
Detecting Cancellation
unsubscribeDetectedAt is set when RevenueCat receives the SUBSCRIPTION_CANCELED RTDN. isActive remains true until the billing period ends. Your app shows a "subscription ends on [date]" message without computing access manually.
Backend Webhooks for Cancellation
Your backend receives:
cancel_reason can be UNSUBSCRIBE (user), BILLING_ERROR (payment failure), DEVELOPER_INITIATED, or PRICE_INCREASE. Use this to segment churned users for win-back campaigns.
Paused Subscriptions
RevenueCat sets isActive = false when a subscription is paused. You do not need to call queryPurchasesAsync() with setIncludeSuspendedSubscriptions(true). The state comes from RevenueCat's server-side subscription state.
If you want to show a "your subscription is paused, resuming on [date]" message, call the RevenueCat REST API (GET /v1/subscribers/{app_user_id}) and read the paused_expiration_time_ms field for the subscription. RevenueCat does not currently send a dedicated webhook event for subscription pauses, the pause state change is reflected via CustomerInfo when RevenueCat processes the Google Play RTDN.
Restoring a Canceled Subscription (Before Expiry)
If a user cancels and then re-subscribes before expiry (Google's "resubscribe before expiry" flow), RevenueCat detects the reactivation via the SUBSCRIPTION_RESTARTED RTDN and sets willRenew = true again. The unsubscribeDetectedAt is cleared. Your app reads customerInfo and the state is correct, no special handling needed.
Resubscribing After Expiry
A resubscription after expiry sends a RENEWAL webhook event, not INITIAL_PURCHASE. INITIAL_PURCHASE fires only for a user's first-ever purchase of a product. Ensure your webhook handler grants entitlement access on RENEWAL as well as INITIAL_PURCHASE, a handler that only listens for INITIAL_PURCHASE will not restore access for users who resubscribe after expiry.
Subscription Deferral (Extending Access)
Subscription deferral is a developer-side operation done through the Google Play Developer API. RevenueCat does not expose a deferral API from the SDK or dashboard. If you need to defer a subscription, you call purchases.subscriptionsv2.defer on the Google Play Developer API directly from your backend.
After deferral, RevenueCat will receive the updated expiry time via RTDN processing and reflect it in CustomerInfo automatically.
Revoking a Subscription
Revocation is also done through the Google Play Developer API directly (purchases.subscriptionsv2.revoke). RevenueCat processes the resulting RTDN and immediately sets isActive = false for the entitlement.
Opening the Subscription Management Screen
Let users cancel or manage their subscription through Google Play:
Win-Back: No SDK Changes Required
Win-back campaigns are configured in the Google Play Console (Play-managed win-back) or in the RevenueCat dashboard (custom targeting). You do not write code to implement win-back. When a win-back offer is accepted, it arrives as a normal purchase and surfaces in CustomerInfo like any other subscription.