Rc Cancellations Pauses Winback

RevenueCat/ai-toolkit/revenuecat-play-billing/skills/rc-cancellations-pauses-winback

作者 RevenueCatccfc038185ec457b2ac9077f3bbf1ba947a44dbbApache-2.0; see LICENSE收录于 2026年10月9日更新于 2026年10月9日

Use this skill when surfacing cancellation, pause, and winback state on Android with RevenueCat. Covers reading unsubscribeDetectedAt, billingIssuesDetectedAt, pause state via periodType, managementURL for deep link, and pause resume date lookup via the REST API.

AI 生成的概览

指导 Android 开发者展示 RevenueCat 的取消、暂停与挽回订阅状态。

功能
说明如何在 Android 上从 RevenueCat CustomerInfo 读取取消、账单问题、暂停与续订状态,包括 unsubscribeDetectedAt、billingIssuesDetectedAt、isActive 和 willRenew。介绍如何用 managementURL 打开 Google Play 订阅管理页面,以及如何通过 RevenueCat REST API 获取暂停恢复日期。还涉及重新订阅流程与挽回相关的 webhook 事件。
适用场景
适用于构建需要展示取消提示、账单问题通知、暂停状态或挽回处理的 Android 订阅界面。也适合在 Play Store 沙盒测试中核对这些状态。
运行要求
使用 RevenueCat SDK 并能获取 CustomerInfo 的 Android 应用;后端需持有 RevenueCat 密钥以调用 subscribers REST 接口。仅为说明文档,不含脚本。

Cancellations, Pauses, and Winback

Detect cancellation, pause, and winback states on Android by reading CustomerInfo. Most of these events are passive: your app observes them rather than initiates them. Open Google Play's manage screen with managementURL. Look up the pause resume date from the REST API.

Phase 1: Scope

Decide what state you need to surface to the user.

StateSignal in CustomerInfoNotes
Canceled, still has accessentitlement.unsubscribeDetectedAt != null and isActive == trueShow "ends on [expirationDate]"
Billing issue (grace or hold)entitlement.billingIssuesDetectedAt != nullPayment failed, recovery in progress
Pausedentitlement.isActive == false while product is still ownedResume date requires REST API
Active and renewingentitlement.willRenew == trueNormal state

Backend win back campaign segmentation uses the CANCELLATION webhook cancel_reason field (UNSUBSCRIBE, BILLING_ERROR, DEVELOPER_INITIATED, PRICE_INCREASE).

Phase 2: Prepare

Confirm you already have a fetched CustomerInfo from Purchases.sharedInstance.getCustomerInfo(...) or a listener. You do not need to call BillingClient.queryPurchasesAsync with setIncludeSuspendedSubscriptions(true). RevenueCat resolves pause state from the server side subscription state.

Rules:

  • managementURL is already Uri?. Pass it straight to the Intent. Do not call Uri.parse(url.toString()).
  • Do not compute access manually from expirationDate. Read isActive and willRenew.
  • Pause resume date is not in the SDK. Fetch it from /v1/subscribers/{app_user_id} in your backend.

Phase 3: Execute

Detect cancellation with remaining access

kotlin
val entitlement = customerInfo.entitlements["pro_access"]if (entitlement?.unsubscribeDetectedAt != null && entitlement.isActive) {    entitlement.expirationDate?.let { expiry ->        showCancellationBanner(expiry)    }}

unsubscribeDetectedAt is set when RevenueCat receives the SUBSCRIPTION_CANCELED RTDN. isActive stays true until the billing period ends.

Detect pause

kotlin
val entitlement = customerInfo.entitlements["pro_access"]val hasAccess = entitlement?.isActive == true// When paused, isActive == false. Pause resume date is not in the SDK.

Open the subscription management screen

kotlin
customerInfo.managementURL?.let { url ->    startActivity(Intent(Intent.ACTION_VIEW, url))}

managementURL is typed as Uri?. Use it directly. Wrapping it with Uri.parse(url.toString()) is redundant and error prone.

Look up pause resume date via REST

From your backend, call the subscribers endpoint and read paused_expiration_time_ms on the subscription:

bash
curl -H "Authorization: Bearer $RC_SECRET_API_KEY" \  https://api.revenuecat.com/v1/subscribers/$APP_USER_ID

The subscription object contains paused_expiration_time_ms when paused. Expose this to your client through your own endpoint.

Resubscribe before expiry

Google's resubscribe before expiry flow fires SUBSCRIPTION_RESTARTED. RevenueCat clears unsubscribeDetectedAt and sets willRenew = true. No extra code required, just re-read customerInfo.

Resubscribe after expiry

A resubscribe after expiry fires a RENEWAL webhook, not INITIAL_PURCHASE. Grant entitlement access on both events in your backend handler.

Phase 4: Verify

CheckHow
Cancellation banner showsCancel in Play Store, pull fresh CustomerInfo, confirm unsubscribeDetectedAt != null and isActive == true
Management deep link opensTap the link, verify Play subscriptions screen opens for the correct product
Pause is reflectedPause in Play Store sandbox, confirm entitlement.isActive == false
Pause resume dateCall /v1/subscribers/{id}, confirm paused_expiration_time_ms is present
Win back acceptedAccept a Play configured win back offer, confirm the purchase surfaces as a normal subscription in CustomerInfo

Notes

  • Deferral and revocation are done through the Google Play Developer API (purchases.subscriptionsv2.defer, purchases.subscriptionsv2.revoke) from your backend. RevenueCat processes the resulting RTDN and updates CustomerInfo automatically.
  • Win back campaigns need no SDK code. They are configured in Play Console or the RevenueCat dashboard.
  • RevenueCat does not currently emit a dedicated pause webhook. Pause state appears in CustomerInfo once the Google Play RTDN is processed.

References

来源与署名

来源:RevenueCat/ai-toolkit位于revenuecat-play-billing/skills/rc-cancellations-pauses-winback提交ccfc038

许可证: Apache-2.0; see LICENSE

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架