Upgrade/downgrade path without re-subscribing
Why it matters
Manually calling cancelSubscription() followed by purchaseSubscription() to move a Monthly subscriber to Annual creates a coverage gap, risks double-charging the user during the transition, and can trigger Play Store purchase rejections because Google expects proration via SubscriptionUpdateParams. The error-resilience cost is high: failed upgrades strand users between plans with unclear entitlement state and drive refund requests. Both platforms ship a first-class upgrade/downgrade path — bypassing it is the failure mode here.
Severity rationale
Low because it only affects users actively changing tiers, though each affected user risks a double charge.
Remediation
Use the platform's native upgrade/downgrade mechanism. On iOS, place all subscription products in the same Subscription Group in App Store Connect — Apple handles proration when the user purchases a higher tier from the same group. On Android, pass the existing purchase token through SubscriptionUpdateParams:
val updateParams = SubscriptionUpdateParams.newBuilder()
.setOldPurchaseToken(currentPurchaseToken)
.setSubscriptionReplacementMode(SubscriptionUpdateParams.ReplacementMode.CHARGE_PRORATED_PRICE)
.build()
For RevenueCat, call purchasePackage() with the target package in the same subscription group — the SDK routes to the platform upgrade path automatically.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the App Store IAP & Subscriptions Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-iap-subscriptions·automated