Solved

Unable to re-purchase a subscription in sandbox.

  • 27 October 2021
  • 25 replies
  • 2654 views

Userlevel 1
Badge +5

I am testing purchasing my subscriptions in sandbox. My device has purchased a subscription before, and it has expired.

When I go in to purchase again, `Purchases.shared.purchasePackage` returns immediately with the `purchaserInfo` and the default entitlement shows my previous purchase, with an isActive status of false. I was never presented with the purchase modal.

 

When I `restoreTransactions`, the `purcahserInfo` shows the same, an expired entitlement. Why can’t I re-purchase an expired subscription?

icon

Best answer by ryan 29 December 2021, 00:56

View original

25 replies

Userlevel 5
Badge +9

Hmmm, do you see any errors or warnings in the debug logs or anything you could attach here? I’ve never had trouble re-purchasing an expired product. 

Userlevel 1
Badge +5

I didn’t see any errors or warnings in the debug log, it said “finishing transaction” just as if I had completed the purchase flow. I cannot reproduce at the moment because I went ahead and deleted my user in order to move forward with what I'm working on….

 

Userlevel 1
Badge +5

@ryan this has happened again. I try to re-purchase a subscription which I let expire, the `purchase` function’s completion block returns right away (without showing the payment sheet), and the entitlement’s `isActive` is false.

 

Here is the debug log, I x’d out my product id for privacy:

 

Purchases] - DEBUG: ℹ️ makePurchase

[Purchases] - DEBUG: 💰 Purchasing product from package  - xxx.xxxx.xxxxx.xxxxxxxx.xxxx.xxx.xx in Offering Annual Only

[Purchases] - DEBUG: ℹ️ PaymentQueue updatedTransaction: xxx.xxxx.xxxxx.xxxxxxxx.xxxx.xxx.xx 1000000900513404 ((null)) 1000000900301520 - 1

[Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///private/var/mobile/Containers/Data/Application/DADDDEC8-8C75-4D83-A1F4-8CB8C24FE39B/StoreKit/sandboxReceipt

[Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: xxxxxxxxxxxx

 [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST /receipts

[Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts

[Purchases] - DEBUG: ℹ️ API request completed with status: POST /v1/receipts 200

[Purchases] - DEBUG: ℹ️ Serial request done: POST /receipts, 0 requests left in the queue

Purchases] - DEBUG: 💰 Finishing transaction xxx.xxxx.xxxxx.xxxxxxxx.xxxx.xxx.xx 1000000900513404 (1000000900301520)

[Purchases] - DEBUG: ℹ️ PaymentQueue removedTransaction: xxx.xxxx.xxxxx.xxxxxxxx.xxxx.xxx.xx 1000000900513404 (1000000900301520 (null)) (null) - 1

Userlevel 1
Badge +5

I did some debugging myself by setting breakpoints in the RevenueCat code.

I set a breakpoint at:

- (void)paymentQueue:(SKPaymentQueue *)queue

updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions

 

line 102 in RCStoreKitWrapper, and when the breakpoint hit, the payment sheet showed. Could it possibly be some sort of race condition where the breakpoint helped?

Badge

I have the exact same issue with my iOS RN app (using "react-native-purchases": "4.4.1"). It simply doesn’t show the payment confirmation dialog for one particular subscription (monthly). For another one (annual) it does.

Nothing in the logs or anywhere. 

Given that it’s my first experience with RevenueCat, I’m wondering if the users in prod aren’t going to have the same issue, so it’s pretty disturbing.

Thank you!

Userlevel 5
Badge +9

Hey @Vladyslav!

A good debugging step here could be to try creating a new sandbox account in App Store Connect and make sure you’re testing on a physical device - not a simulator. Apples doesn’t give developers (including RevenueCat) any control over when/how the payment sheet or confirmation dialog appears so these types of issues are often related to the underlying Apple account or device. 

Badge +3

hei, 

I am getting the exact same issue with Flutter SDK and iOS real device. Sometimes (not always, which is really the worst part) when I try to repurchase the call simply goes through without throwing any exception and without bringing the native subscription dialog to allow the user to purchase. This happens with the monthly subscription and the yearly subscription works as expected (Exactly as Vladyslav above states). I am not testing the yearly subscription enough as it takes more time so perhaps that could be the reason.

This is quite disturbing as I definitely do not want to see this in production. I have been using qOnversion until now and I thought I should switch but now I am quite conflicted about it. Any help is greatly appreciated.

Here is the flutter code:

final purchaserInfo = await Purchases.purchasePackage(package_monthly!);

And here is the purchaserInfo object that is returned but again, no exception is thrown and no purchase native dialog is show to the user:

flutter: PurchaserInfo(entitlements: EntitlementInfos(all: {premium: EntitlementInfo(identifier: premium, isActive: false, willRenew: false, latestPurchaseDate: 2022-05-27T11:48:03Z, originalPurchaseDate: 2021-07-30T06:01:32Z, productIdentifier: monthly_light, isSandbox: true, ownershipType: OwnershipType.purchased, store: Store.appStore, periodType: PeriodType.normal, expirationDate: 2022-05-27T11:53:03Z, unsubscribeDetectedAt: 2022-05-27T13:48:05Z, billingIssueDetectedAt: null)}, active: {}), allPurchaseDates: {monthly_light: 2022-05-27T11:48:03Z}, activeSubscriptions: [], allPurchasedProductIdentifiers: [monthly_light], nonSubscriptionTransactions: [], firstSeen: 2022-05-27T13:47:58Z, originalAppUserId: $RCAnonymousID:d4bc9b9838994c749e04da9986254524, allExpirationDates: {monthly_light: 2022-05-27T11:53:03Z}, requestDate: 2022-05-27T15:28:20Z, latestExpirationDate: 2022-05-27T11:53:03Z, originalPurchaseDate: 2013-08-01T07:00:00Z, originalApplicationVersion: 1.0, managementURL: null)

 

Btw, I also can not find the originalAppUserId in the sandbox dashboard (from the purchaserInfo object above)

Badge

Hey,

I was also experiencing same issue on iPhone with flutter. Yesterday it was working fine but now i am having issue repurchasing product.

 

When i try to repurchase same subscription with purchasePackage function it returns below package without showing In app purchase dialog box.

 

EntitlementInfo{identifier: Premium, isActive: false, willRenew: false, periodType: PeriodType.normal, latestPurchaseDate: 2022-06-10T07:04:54Z, originalPurchaseDate: 2022-05-24T10:34:49Z, expirationDate: 2022-06-10T07:07:54Z, store: Store.appStore, productIdentifier: vc_599_1m_1m0, isSandbox: true, unsubscribeDetectedAt: 2022-06-10T07:16:33Z, billingIssueDetectedAt: null, ownershipType: OwnershipType.purchased}

 

This problem only occur when i try to repurchase same subscription if i choose different plan then everything working as expected.

 

I am thinking maybe it is some sort of caching issue. Any help would be appreciated as this is blocking our app roll out.

Badge +2

I’d like to bump this thread as I’m running into the exact same issue in versions `5.0.0-beta.4` and `5.0.2`. on a physical iOS device. The issue is exactly as described above. I have a sandbox account that has purchased a monthly subscription which has since expired. When calling `Purchases.purchasePackage` the checkout screen is never presented and the promise is resolved with an empty `activeSubscriptions` and `entitlements.active` on the `customerInfo` object.

Userlevel 5
Badge +8

We’ve had a few reports of this and it seems to be an issue with StoreKit 1. Upgrading to using an SDK version that allows you to use StoreKit 2 under the hood should help. 

The latest version of our iOS, Flutter, React-Native and Unity SDKs support StoreKit 2, by passing an extra parameter when configuring. 

 

Could you give it a shot? Let me know if you need instructions for any particular SDK. 

Badge

Also running into the same issue using new accounts and physical devices and the latest StoreKit2 version. Did anyone try this in production ? 

Badge

Update: Looks like it’s a bug with older iOS versions (was testing on iOS 15.2). The code works on newer versions of iOS without any issue. Works on iOS 15.7 and above. 

Badge +2

I’m experiencing the same issue on iPad mini with iPadOS 15.7 with Flutter SDK. I’m using a sandbox apple id account and when trying to resubscribe, no native buy subscription dialog is showing up and the subscription is not renewed. It basically silently dies and thus the buy-subscription workflow is broken. This is an annual sub I bought before and it already expired.

 

If I try to buy a monthly subscription that I had never bough before (it is using the same implementation code in my app) the native dialog does show up.

 

@Andy I’m a bit confused about StoreKit 2 - you said it can be enabled with a config option. However this article states that it’s somehow automatically handled by Revenue Cat? https://www.revenuecat.com/blog/storekit-2-overview/

 

If you’re a RevenueCat customer, you won’t have to worry about supporting Storekit 1 and StoreKit 2 simultaneously—we’ll do it for you, and we’ll use the new system wherever it’s available. 

 

Could you please clarify. And if it indeed has to be enabled manually via the config, how to do this in Flutter? I was unable to find instructions on that. 

 

Thank you so much, RevenueCat Team! 

Userlevel 5
Badge +8

@Tomek we’re still investigating, but there seems to be an issue where some versions of iOS don’t always finish transactions correctly. When this happens, initiating a purchase doesn’t open up the paywall and instead it’s marked as completed right away. We’re working on fixing this. 

 

As for the StoreKit 2 bit, basically RevenueCat automatically chooses which version of StoreKit to use, but we also allow developers to choose if they wish. Our most recent SDKs default to StoreKit 2. 

Badge +5

I’m seeing the same issue today using iOS 15.7 and RC SDK 4.13.2 (I didn’t change any settings relating to using StoreKit 2 so RC should be using whatever it uses by default). Basically I purchased a subscription (in the sandbox) then after it expired calling Purchases.shared.purchase() just returns immediately without showing the purchase sheet, the response shows the old expired subscription.

 

Some output from the logs:

2022-11-09 16:43:11.806963-0800 [Purchases] - INFO: 💰 Purchasing Product 'com.foo.monthlySub’

2022-11-09 16:43:11.919374-0800 [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.

2022-11-09 16:43:12.911615-0800 [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///private/var/mobile/Containers/Data/Application/ED556239-F1B4-4C0E-B922-0580AFB56111/StoreKit/sandboxReceipt

2022-11-09 16:43:12.911727-0800 [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["com.foo.monthlySub"]

2022-11-09 16:43:12.911796-0800 [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["com.foo.monthlySub"]

2022-11-09 16:43:12.912392-0800 [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: 1234

2022-11-09 16:43:12.916434-0800 [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started

2022-11-09 16:43:12.929352-0800 [Purchases] - INFO: ℹ️ Receipt parsed successfully

2022-11-09 16:43:12.935259-0800 [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {

  "in_app_purchases" : [

      "original_purchase_date" : "2022-11-09T23:36:27Z",

      "purchase_date" : "2022-11-09T23:39:25Z"

2022-11-09 16:43:12.936304-0800 [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts

2022-11-09 16:43:12.939156-0800 [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts

2022-11-09 16:43:13.639018-0800 [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200

2022-11-09 16:43:13.647729-0800 [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished

2022-11-09 16:43:13.648655-0800 [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue

2022-11-09 16:43:13.651993-0800 [Purchases] - INFO: 💰 Finishing transaction '2000000198291609' for product 'com.foo.monthlySub'

2022-11-09 16:43:14.170475-0800  [Purchases] - INFO: 😻💰 Purchased product - 'com.foo.monthlySub'

Userlevel 5
Badge +8

@mrd does retrying after that work? This behavior seems to happen when StoreKit silently fails to finish a transaction for the product. Based on the logs, the SDK is trying to finish it again, so that’s why I’m wondering whether retrying solves it. 

 

It looks like a part of the logs there is truncated, particularly the part that printed the receipt. Do you have more logs from it? 

 

Do you also get this issue if you upgrade to the latest version? Currently that’s 4.14.1. 

 

Badge +5

@Andy eventually after retrying multiple times the purchase sheet will pop up, I think once after about 5 times of trying to purchase, then after reproducing again about 10 times.  I can’t get all the logs they are truncated in xcode and console.app

 

I can reproduce this issue every time though on iOS and the sandbox. I always create a new sandbox user each time for testing, not sure if that would have anything to do with it and I am seeing it for monthly subscription renewal, again not sure if that is part of the issue or not. It’s too painful to try to test all this with longer expiring subscriptions.

 

Here is the log output from the latest time I tried it, there is a bit more of the receipt in the output:

14:58:56.248146-0800 simple-weather [Purchases] - INFO: 💰 Purchasing Product 'com.x.weather_beta.monthBeliever'

14:58:56.307439-0800 simple-weather [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.

14:58:57.386151-0800 simple-weather [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///private/var/mobile/Containers/Data/Application/063E9BC9-C1BC-4BAD-868A-4B62A940B69F/StoreKit/sandboxReceipt

14:58:57.386482-0800 simple-weather [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["com.x.weather_beta.monthBeliever"]

14:58:57.386662-0800 simple-weather [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["com.x.weather_beta.monthBeliever"]

14:58:57.389131-0800 simple-weather [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: 2D88CDA8-0B40-4407-9657-459F371F0109

14:58:57.390461-0800 simple-weather [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started

14:58:57.402915-0800 simple-weather [Purchases] - INFO: ℹ️ Receipt parsed successfully

14:58:57.404861-0800 simple-weather [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {

  "opaque_value" : "DukuhUBW5Y+YZWf\/UVVesw==",

  "original_application_version" : "1.0",

  "bundle_id" : "com.x.weather-beta",

  "sha1_hash" : "Bv46Ldxj51Q1LJzWLjhiH+6FMks=",

  "application_version" : "2",

  "creation_date" : "2022-11-10T22:58:57Z",

  "in_app_purchases" : [

    {

      "product_id" : "com.x.weather_beta.monthBeliever",

      "quantity" : 1,

      "transaction_id" : "2000000199579483",

      "is_in_trial_period" : false,

      "is_in_intro_offer_period" : false,

      "expires_date" : "2022-11-10T22:21:59Z",

      "web_order_line_item_id" : 2000000014617087,

      "original_purchase_date" : "2022-11-10T22:14:01Z",

      "original_transaction_id" : "2000000199578995",

      "product_type" : 3,

      "purchase_date" : "2022-11-10T22:16:59Z"

    },

    {

      "product_id" : "com.x.weather_beta.monthBeliever",

      "quantity" : 1,

      "transaction_id" : "2000000199582633",

      "is_in_trial_peri

14:58:57.404980-0800 simple-weather [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts

14:58:57.407680-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts

14:58:58.465378-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200

14:58:58.473654-0800 simple-weather [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished

14:58:58.473829-0800 simple-weather [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue

14:58:58.476100-0800 simple-weather [Purchases] - INFO: 💰 Finishing transaction '2000000199590967' for product 'com.x.weather_beta.monthBeliever'

14:58:58.990742-0800 simple-weather [Purchases] - INFO: 😻💰 Purchased product - 'com.x.weather_beta.monthBeliever'

14:58:58.992403-0800 simple-weather [Purchases] - DEBUG: ℹ️ GetCustomerInfoOperation: Started

14:58:58.992698-0800 simple-weather [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request GET subscribers/2D88CDA8-0B40-4407-9657-459F371F0109

14:58:58.995170-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request started: GET /v1/subscribers/2D88CDA8-0B40-4407-9657-459F371F0109

14:58:59.494420-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request completed: GET /v1/subscribers/2D88CDA8-0B40-4407-9657-459F371F0109 200

14:58:59.506535-0800 simple-weather [Purchases] - DEBUG: 😻 CustomerInfo updated from network.

14:58:59.506692-0800 simple-weather [Purchases] - DEBUG: ℹ️ GetCustomerInfoOperation: Finished

14:58:59.506943-0800 simple-weather [Purchases] - DEBUG: ℹ️ Serial request done: GET subscribers/2D88CDA8-0B40-4407-9657-459F371F0109, 0 requests left in the queue

14:58:59.507030-0800 simple-weather [Purchases] - DEBUG: ℹ️ GetCustomerInfoOperation: Started

14:58:59.507155-0800 simple-weather [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request GET subscribers/2D88CDA8-0B40-4407-9657-459F371F0109

14:58:59.509388-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request started: GET /v1/subscribers/2D88CDA8-0B40-4407-9657-459F371F0109

14:58:59.694612-0800 simple-weather [Purchases] - DEBUG: ℹ️ API request completed: GET /v1/subscribers/2D88CDA8-0B40-4407-9657-459F371F0109 200

14:58:59.705379-0800 simple-weather [Purchases] - DEBUG: 😻 CustomerInfo updated from network.

14:58:59.705722-0800 simple-weather [Purchases] - DEBUG: ℹ️ GetCustomerInfoOperation: Finished

14:58:59.705975-0800 simple-weather [Purchases] - DEBUG: ℹ️ Serial request done: GET subscribers/2D88CDA8-0B40-4407-9657-459F371F0109, 0 requests left in the queue

Badge +3

@mrd just wanted to say that your steps to “fix” the issue about subscribing about 10 times does in fact eventually force the buy flow to open up.

Experiencing the same exact issue everyone has described. Based on the logs it is successful. Returns the PurchaseInfo just fine. But the entitlement status is not active. Which sounds like it could be a cache issue. Hoping it’s just sandbox related.

Badge +2

Was there ever a resolution on this? We’ve been seeing the same thing on our end with RN on iOS (Haven’t confirmed on Android yet) 

Testing on physical device (15.5) iPhone XR - react-native-purchase version 4.6.0. 

Step to reproduce in sandbox:

  • Subscribe to a product (monthly) 
  • Renew a couple of times
  • Manually cancel subscription and reset promotion eligibility from iPhone developer settings. 
  • Delete sandbox customer from RevCat dashboard
  • Purchaser Info shows no active subs, but shows the expired sub 
  • Subscribe to package
    • The purchase package function returns right away showing an active sub, however, no subscription is actually made and the sheet does not pop. 

We’ve been brute forcing it by just reloading, open/closing the app and after several times it will work.

Is there a definitive answer that this issue is isolated to Sandbox or are others also seeing it in Production? If so, are there detailed steps on how to fix? Thanks! 

Badge +2

Was there ever a resolution on this? We’ve been seeing the same thing on our end with RN on iOS (Haven’t confirmed on Android yet) 

Testing on physical device (15.5) iPhone XR - react-native-purchase version 4.6.0. 

Step to reproduce in sandbox:

  • Subscribe to a product (monthly) 
  • Renew a couple of times
  • Manually cancel subscription and reset promotion eligibility from iPhone developer settings. 
  • Delete sandbox customer from RevCat dashboard
  • Purchaser Info shows no active subs, but shows the expired sub 
  • Subscribe to package
    • The purchase package function returns right away showing an active sub, however, no subscription is actually made and the sheet does not pop. 

We’ve been brute forcing it by just reloading, open/closing the app and after several times it will work.

Is there a definitive answer that this issue is isolated to Sandbox or are others also seeing it in Production? If so, are there detailed steps on how to fix? Thanks! 

Update on this - We updated `react-native-purchase` to 5.0.0 which did not resolve the issue. We then added ‘usesStoreKit2IfAvailable’ to Purchases.set() and it is now working.

Badge

I have exactly the same issue. Standard purchase sheet doesn’t pop up, password text input doesn’t appear. StoreKit reports successful purchase but `purchasedProductIDs` is empty eventually.

I don’t use RevenueCat framework, however I used the code from RevenueCat StoreKit2 guide to implement iAP https://www.revenuecat.com/blog/engineering/ios-in-app-subscription-tutorial-with-storekit-2-and-swift/

Tapping the purchase button 10 times appears to be fixing the issue. The purchase confirmation sheet eventually appears and resubscribe transaction is handled correctly!

 

Badge

Haha can confirm that mashing the button repeatedly eventually causes the form to appear again 😅 Ran into this recently as well with a similar repro case on iOS 17.

Badge +3

Also experiencing this issue. Just hanging at [purchases] INFO: 💰 Finishing transaction. Tried creating a new Sandbox account too. Tried multiple versions of the SDK too.

I am also experiencing this in the sandbox (same as NK above, I’m not using RevenueCat anymore but followed that guide). Haven’t shipped to production yet but really hoping this is isolated to the sandbox

Badge +1

I can confirm this happens in production. Just got off the phone with a customer facing this blocker. Their situation was this:
 

  1. They subscribed to one subscription (Starter subscription).
  2. After they subscribed to a premium subscription (Premium subscription).
  3. They tried to switch back to Starter subscription, but could not because Apple payment sheet does not appear. 

I am using react-native-iap, not react-native-purchases, so this must be an Apple issue. Looking into a way to handle this. Will report back.

Reply