Question

A recovered Android subscription was cancelled because it was not acknowledged by the API.

  • 3 October 2022
  • 7 replies
  • 204 views

Badge +3

In our testing, we tried a sandbox PurchaseProduct on Android that resulted in a code 10 network error:


"message": "Error performing request.",
"context": "PurchaseProduct",
"underlyingErrorMessage": "Hostname api.revenuecat.com not verified:\n certificate: sha1/3LiOs5Y962AdAv8grdgm7+0i67g=\n DN: CN=*.gci-mckinsey.com\n subjectAltNames: [*.gci-mckinsey.com]",
"readableErrorCode": "NetworkError",
"code": 10

 

The tester then attempted to purchase the same subscription and got a code 6 (ITEM_ALREADY_OWNED). Because of this, our app triggered a SyncPurchase, resulting in a subscribed status for the user after a few seconds.

 

However, a email was promptly sent to our tester by GooglePlay about the subscription being cancelled as in that scenario, no acknowledgement had apparently been sent by Revenue Cat.

 

So apart from the network issue, the concern for us is that recovered transactions are not acknowledged by the API. If it can help debug, the UserID is DBE441C2AD27727E

 

To try to mitigate this issue, we plan to now do an Android Restore when receiving a network error on a PurchaseProduct. Especially since we can expect a callback in that case (SyncPurchase is a simple synchronous call). Would this be enough?

Is there a better option to recover from a network error on a PurchaseProduct? What is the API retrying pattern for network errors on a PurchaseProduct?


7 replies

Userlevel 5
Badge +8

@Gabriel_Ulu 

In cases like this, calling `SyncPurchases` should solve it. `RestorePurchases` is similar, but on iOS it could trigger a prompt to log in to App Store, so we recommend tying usages of `RestorePurchases` to Restore buttons or other user actions, so the user isn’t confused about why they get the prompt. 

`SyncPurchases` should be safe to use. 

 

That being said, it would be great to identify why this issue `Hostname api.revenuecat.com not verified` is happening - it’s certainly not usual. I think I remember you showing me you were getting random SSL issues with our backend on iOS as well? Is this still true? Do you ever get that kind of issue with other domains? 

Badge +3

In cases like this, calling `SyncPurchases` should solve it. `RestorePurchases` is similar, but on iOS it could trigger a prompt to log in to App Store, so we recommend tying usages of `RestorePurchases` to Restore buttons or other user actions, so the user isn’t confused about why they get the prompt. 

`SyncPurchases` should be safe to use. 

 

In the case I described, SyncPurchases was actually called. It resulted in the account being linked to the valid subscription, as expected.

What was not expected is the early cancellation email from Apple. Because the purchase had never been acknowledged and marked as processed. E.G.: (1) It was not acknowledged on the actual transaction, likely because of the network error, and (2) was not acknowledged on the SyncPurchase either. 

 

That being said, it would be great to identify why this issue `Hostname api.revenuecat.com not verified` is happening - it’s certainly not usual. I think I remember you showing me you were getting random SSL issues with our backend on iOS as well? Is this still true? Do you ever get that kind of issue with other domains? 

 

I agree that this is kind of a different issue and it would be great to figure it out.

I do not remember having seen a similar error outside of RevenueCat. That being said, we do have quite intricate retry patterns on all the network calls we are managing. That was why I was also asking about “if” or “how” receipt posts are retried by RevenueCat’s SDK in case of errors in such a crucial network call. 

We do get SSL errors on iOS along those lines:

	"underlyingErrorMessage": "An SSL error has occurred and a secure connection to the server cannot be made.",
"message": "Error performing request.",
"readableErrorCode": "NETWORK_ERROR",
"code": 10

On both Android and iOS, these errors do not tend to repro for very long. This is why the crucial part of this thread is about ways to recover from this kind of errors.

 

Badge +5

Here are our latest findings, in case this helps other developers. We’re using the Unity SDK version 4.5.2.

Our goal is to understand how the SDK recuperates from network errors or other types of failures halfway through the purchase process. The purchase can go through with the platform, but nothing guarantees that the call to RevenueCat will succeed after (the app could be killed, network problems can occur, RevenueCat servers can be down, etc). While we have noticed various errors during regular testing (see above), the way we reproduce these issues is by disconnecting the network halfway through the transaction. These tests were done in sandbox mode.

iOS

Repro steps: start the renewable subscription process. When the native dialog “You’re all set!” shows up, we make the WIFI unavailable, then click ok. The subsequent call to RC fails. We make the WIFI available again, then our code calls SyncPurchases.

Result: the subscription is properly recuperated and will renew, as expected.

Android
Repro steps: start the renewable subscription process. When the native dialog with a green checkmark shows up, we quickly put the device in airplane mode. The subsequent call to RC fails. We disable airplane mode, then our code calls SyncPurchases.

Result: RevenueCat finds the subscription, but the subscription is in a state that will get canceled by Google Play. In the play store, it says "Confirm plan" and "Open this app to confirm your plan before <sub end date>". Force closing and reopening the app does not change this status, and the subscription eventually gets canceled by Google.

Expected: for RevenueCat to confirm the transaction with Google either on app start or when doing a call to SyncPurchases().

In case of a network error, we also tried triggering the purchase process again. The native dialog from Google says that the subscription already exists, RC sees the entitlement, but the subscription is in the same "will be canceled" state.

We're not aware of a way for users to recuperate from this type of in the app buying process. The transaction clearly went through on the platform, but the SDK doesn't seem to handle this like Google Play would want. Any thoughts on this would be appreciated. I'm tagging @cody  since we've been talking through customer support about this.

Thanks.

Userlevel 5
Badge +8

Hey @Ululab, thanks for the detailed info. Let me try to get some more info on why these transactions might not be getting acknowledged on Android.

Badge +5

Thanks @cody ! In case this helps, I’m finding a different behaviour with different repro steps on android:

Repro steps: start the renewable subscription process. When the native dialog with a green checkmark shows up, we kill the app.

Result: In the play store, it says "Confirm plan" and "Open this app to confirm your plan before <sub end date>". If I open the app again, the subscription is now confirmed and will autorenew as expected.

It seems like force quitting the app is properly handled, but not network errors.

Badge +5

@cody last details on this: on android, if we do a restore purchase instead of a SyncPurchases() after a network error, we are actually in a good state - Google Play shows the subscription as renewable. We wouldn’t want to do this on iOS since it can pop a native dialog that would be confusing for users.

So as it stands, our current solution in case of a network error would be to do a SyncPurchases on iOS, and a restore purchases on android. Please let us know if you have a different recommendation after checking with the team though, as the information we were able to find online suggests we should be relying on SyncPurchases instead.

Thanks!

Userlevel 5
Badge +8

Hey @Ululab,

Thanks for the additional information; I think that’s a good way forward at this time - I’ll share this feedback with the SDK team for more improvement, and I’ll see if there’s a way we can get this documented properly.

Reply