Error consuming purchase with token. Response code: 8

Hello,

I am trying to get started with Consumable IAP on Android.

My general flow based on the IAP sample and Unity - Manual: Processing Purchases is

1 I call InitiatePurchase
2 Unity calls ProcessPurchase
2 a) I start a Coroutine that send the receipt to my server
2 b) I return PurchaseProcessingResult.Pending
3 Coroutine sends a request to my server
3 a) Server consumes the purchase using Google’s API
3 b) Server adds the consumable to the user’s account
3 c) Server sends back a response
4 Coroutine calls ConfirmPendingPurchase

The issue I am seeing is that sometimes, somewhere between 3 c) and 4 (or during 4?) I see OnPurchaseFailed get triggered and the logs say

Error consuming purchase with token. Response code: 8
onPurchaseFailedEvent(productId:premium_credits_10 message:Item is not owned by the user. {code: ItemNotOwned, M: GPSFTS.HFT})

I suspect this is maybe because there is a race and 4 ends up being called before 2 b) happens? Or it may be because I am consuming the purchase on the server side and then ConfirmPendingPurchase tries to do it again on the client?

So my questions are:

  1. What is the correct usage of ConfirmPendingPurchase in this case? In the IAP sample it’s bound to a button - surely we are not meant to ask the user to tell us this?
  2. a. Since I am consuming the purchase myself on the server, do I even need to call ConfirmPendingPurchase at all? Unity - Manual: Processing Purchases implies that the unity IAP API will consume the purchase (I don’t want this, since this means that between when I credit the user on the server and when the purchase gets consumed there is a gap during which many bad things can happen, invalidating the transaction).
  3. How do deferred purchases factor into this? (AFAICT I just have to wait for ProcessPurchase to get called with store extension IsDeferred returning false?

Hello rpolyano,

  1. ConfirmPendingPurchase is used to finish the transaction. This informs the store that the user was granted their purchase. In cases like the Google Play Store, a purchase that isn’t confirmed will be refunded after 72h to protect the user. You can either use the automatic confirmation if you don’t do any additional validations or you can intercept the purchase with ProcessPurchase and then do the call to ConfirmPendingPurchase when you have finished validating and awarding the purchase on your end.
  2. No, since you are already doing it server side, you don’t have to call ConfirmPendingPurchase on the client side. Your call on the server side is the same thing.
  3. For deferred purchases, those haven’t been paid yet, so you don’t have to do anything about them. You can simply wait for non deferred purchases to reach ProcessPurchase.

Thank you for the detailed reply!

My followup here is that since my server validation flow happens in an async coroutine, which is started from ProcessPurchase, what should I return from process purchase while it runs? If I return Pending then it expects me to call ConfirmPendingPurchase, so do I just return complete, even though the purchase validation may fail on the server?

Since you do purchase validation on your server, you should return Pending in ProcessPurchase.
When the server validation is successful, you want to call the ConfirmPendingPurchase, otherwise, do nothing.

Right, so this is what I did, and so I was getting the error I mentioned in the original post.

Sorry, I forgot to refer to your initial post with my last reply.

Since you are consuming the purchase on the server side, then you don’t want to call ConfirmPendingPurchase on the client side (it does the same thing) since you can only consume it once.
You also want to return Pending to ProcessPurchase, this makes it not call ConfirmPendingPurchase (this is the only additional call we do when ProcessPurchase returns Complete).

1 Like

Thanks Yannick, so just to confirm, I return Pending and never confirm it in unity (only on my server, directly with the google play/ios stores). There are no repercussions to this (unity won’t revert/refund the purchase or something after some timeout?).

Correct, just return pending and never confirm in Unity, then confirm through your server.

The case you’re worried about seems to be the 72h refund on the Google Play Store, you can test this with the test-card, if something goes wrong, it will be refunded in 3 minutes:

Once you confirmed the purchase on your server, you will be able to see that the transaction was confirmed on your Google Play Console in the Order Management and it won’t get refunded.

Another test you can do is doing a restore transaction or closing/reopening the application. All the pending purchases will be sent to the ProcessPurchase again. If you confirmed the purchase, you won’t see it go through the ProcessPurchase.

1 Like