Loading...
Loading...
Use this skill when implementing subscription upgrades, downgrades, and plan switches via RevenueCat on Android. Covers GoogleProductChangeInfo, picking a Google replacement mode, and letting the SDK manage linkedPurchaseToken chaining.
npx skill4agent add revenuecat/ai-toolkit rc-plan-changesPurchaseParamslinkedPurchaseTokenCustomerInfoPurchases.sharedInstance.awaitCustomerInfo()Packageofferings.currentfetch-offeringsmake-purchaseGoogleReplacementMode| Scenario | Mode | Billing effect |
|---|---|---|
| Standard upgrade (monthly to annual) | | Immediate switch, remaining time credited |
| Upgrade, keep the existing billing date | | Immediate switch, prorated charge now |
| Switch to or from a prepaid plan | | Immediate switch, full charge now |
| Upgrade during an active free trial | | Immediate switch, prorated charge now |
| Downgrade (annual to monthly) | | Switch applies at next renewal |
WITHOUT_PRORATIONWITHOUT_PRORATIONCHARGE_PRORATED_PRICEPurchaseParamsWITHOUT_PRORATIONDEFERREDcurrentProductIdCustomerInfoval customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
// activeSubscriptions entries are "productId:basePlanId", strip the base plan suffix
val currentProductId = customerInfo.activeSubscriptions
.firstOrNull()
?.substringBefore(":")
?: return // nothing active, route to make-purchase instead
val newPackage = offerings.current
?.availablePackages
?.firstOrNull { it.identifier == "premium_annual_package" }
?: return
val params = PurchaseParams.Builder(activity, newPackage)
.googleProductChangeInfo(
GoogleProductChangeInfo(
oldProductId = currentProductId,
replacementMode = GoogleReplacementMode.WITH_TIME_PRORATION,
)
)
.build()
try {
val result = Purchases.sharedInstance.awaitPurchase(params)
// result.customerInfo reflects the new subscription
} catch (e: PurchasesTransactionException) {
if (!e.userCancelled) showError(e.error.message)
}oldProductId"basic_monthly:monthly_plan":monthly_planCustomerInfo.activeSubscriptionsproductId:basePlanIdsubstringBefore(":")CustomerInfocustomerInfo.activeSubscriptionsproductId:basePlanIdcustomerInfo.entitlements["pro"]?.isActivetrueDEFERREDactiveSubscriptionslinkedPurchaseToken| Mistake | Fix |
|---|---|
Hardcoding | Derive it from |
Passing | Slice off the base plan with |
Using | Use |
Using | |
Writing backend code to follow | RevenueCat does this server side, delete the code |
| Reading the SKU to decide UI state | Read |