Unity IAP doesn't consume consumable acknowledged purchases

Unity IAP doesn’t consume consumable acknowledged purchases.

I am using up to date (Google Issue Tracker) Method: purchases.products.acknowledge on the server to acknowledge purchases.

I know, that PurchaseProcessingResult.Complete automatically acknowledges purchases. But I should Acknowledge purchase on the server side to fight frauds, because my game is online game and player’s inventory is stored on the server.

Acknowledged consumable product starts to behave as Non-consumable in Unity IAP, because App doesn’t allow to purchase it again and tries to purchase it every app reinstall.

How to reproduce the problem:

  1. BuyProductID;
  2. On ProcessPurchase send receipt to server;
  3. Optional: On the server validate receipt and give the player product, if everything is ok;
  4. Important: Acknowledge purchase to avoid refund after 3 days. (I am using .NET and Google.Apis.AndroidPublisher.v3 - Purchases.Products.Acknowledge());
  5. On ProcessPurchase return PurchaseProcessingResult.Pending;
  6. Close the App;
  7. Wait a minute;
  8. Relaunch App and Consumable product becomes “Non-Consumable” and all problems, listed before, appears.

What is not working as expected:

  1. BuyProductID - ProcessPurchase - PurchaseProcessingResult.Pending - Purchases.Products.Acknowledge() on the server - Relaunch app - ProcessPurchase - PurchaseProcessingResult.Complete
  2. BuyProductID - ProcessPurchase - PurchaseProcessingResult.Pending - Purchases.Products.Acknowledge() on the server - Relaunch app - ProcessPurchase - PurchaseProcessingResult.Pending - ConfirmPendingPurchase

And after this two ways, the player’s account become “broken”. He can’t buy this product again and this product will ProcessPurchase every app reinstall

And also,
What is not working as expected:

  1. Redeem promo code in Google Play - Google automatically Acknowledge - Open App - ProcessPurchase - PurchaseProcessingResult.Complete
  2. Redeem promo code in Google Play - Google automatically Acknowledge - Open App - ProcessPurchase - PurchaseProcessingResult.Pending - ConfirmPendingPurchase
  3. Redeem promo code in app - Google automatically Acknowledge - ProcessPurchase - PurchaseProcessingResult.Pending - Relaunch app - ProcessPurchase - PurchaseProcessingResult.Complete
  4. Redeem promo code in app - Google automatically Acknowledge - ProcessPurchase - PurchaseProcessingResult.Pending - Relaunch app - ProcessPurchase - PurchaseProcessingResult.Pending - ConfirmPendingPurchase

The player’s account becomes “broken” too, because the product, redeemed with promo code, is acknowledged immediately by Google, but not consumed.

It is the same issue: Unity IAP doesn’t consume consumable acknowledged purchases.

More about these problems here:

Please, fix this problem.

Logs with detailed description. My code is almost the same as Sample IAP Project. All Debug.Log statements on the same place.

1.txt - First launch of app with new account and new product - Works good.
2.txt - BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Complete - Works good.
3.txt - Again BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Complete - Works good.
4.txt - Relaunch app - Works good.
5.txt - Again BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Complete - Works good.
6.txt - Relaunch app - Works good.
7.txt - BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Pending - Works good.
8.txt - Again try BuyProductID - Works good.
9.txt - Relaunch app - ProcessPurchase - return PurchaseProcessingResult.Pending - Works good.
10.txt - Again try BuyProductID - Works good.
11.txt - Relaunch app - ProcessPurchase - return PurchaseProcessingResult.Complete - Works good.
12.txt - BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Complete - Works good.
13.txt - Relaunch app - Works good.
14.txt - BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Pending - Works good.
Now Purchases.Products.Acknowledge() on the server, using developer payload = null, AndroidPackageName, purchaseId and purchaseToken from receipt:
AndroidPublisherService().Purchases.Products.Acknowledge(null, AndroidPackageName, purchaseId, purchaseToken);
15.txt - Again try BuyProductID - ProcessPurchase - return PurchaseProcessingResult.Pending - Not working. Unity IAP tries to ProcessPurchase after PurchaseFailureReason: DuplicateTransaction. Compare working 8.txt with 15.txt.
16.txt - Relaunch app - ProcessPurchase - return PurchaseProcessingResult.Complete - Not working. Compare working 11.txt with 16.txt
17.txt - try BuyProductID - Not working.
18.txt - Relaunch app - Not working.
19.txt - try BuyProductID - Not working.
20.txt - Reinstall app - ProcessPurchase - return PurchaseProcessingResult.Complete - Not working.
21.txt - try BuyProductID - Not working.

7008488–828950–logs.zip (10.5 KB)

Do not acknowledge products server side, we do this for you on the client. The behavior is not guaranteed. The typical flow is to validate receipts only server side. You return Complete from ProcessPurchase, but do not award the product if the receipt validation fails.

@JeffDUnity3D Just to clarify, are you saying to support Unity IAP servers have to implement their own system to acknowledge fulfilled purchases?

Nope, it’s all done on the client. Don’t acknowledge purchases on a server, just validate the receipts.

Fulfillment happens on the server not the client. If you don’t mark a receipt as acknowledged they can just send it again.

If you don’t have a mechanism to mark a receipt as acknowledged and the server is simply validating the receipt and then fulfilling it, then that receipt can be sent again unless the server has some way of marking the receipt as fulfilled.

Yes, we acknowledge on the client. Users can buy as many consumables as they want. The store APIs won’t let the user purchase a non-consumable or subscription more than once. You are free to do fulfillment on the server, but don’t acknowledge the product there. We already do that for you. If you can offer steps to reproduce without using a server, we may be able to see if there is any issue at our end. Perhaps you could use Postman or similar from a local PC.

The issue is google recommends using acknowledgement to mark purchases as fulfilled. But a game with servers has fulfillment happen on the server not the client.

1 Like

I realize I’m just reiterating. I can try and give and basic example. You have a gems stored on a server. The user buys gems from the playstore gets a receipt for the purchase and sends it to the server for validation. However before the server can send a response to the client the user disconnects. However the server did get the receipt, the server validates the receipt it passes validation and they give the user gems. At this point google recommends that you mark that purchase as acknowledged because the purchase has been fulfilled. If you don’t do that then the user boots up again, the purchase comes in again because it’s marked as pending so the user sends the receipt to be validated again. The server gets it and without any system for marking receipts as acknowledged goes and validates the receipt again and gives the user gems again.

Now if the server does mark the purchase as acknowledged then the user can’t send the receipt again because it’s already acknowledged. However since Unity IAP filters our acknowledged receipts from finishing transaction. The purchase is lost in the system and you can’t buy gems anymore.

As mentioned, you will need to provide specific steps to reproduce without a server. We have no way to try to reproduce this. More importantly, if there is an issue at our end, we would need to use the same steps to confirm any potential fix.

There are a ton of receipt validation examples. Here’s the first one that shows up on google. How to check if in-app purchase/subscription is valid? (Node.js) | by Nikita Pustovoi | AndroidHub | Medium

You’ll notice that they acknowledges receipts as well. So this example won’t work with Unity IAP (after the newer updates). You’ll get the same error OP and I get.

That article is very old. And they are only validating the receipt, not acknowledging the product. onConsumeFinished is done on the client in that example. We are now using the Google Billing Library v3. If you want us to take a look, you will need to provide steps to reproduce without a server. You should be able to make a simple Google API call to reproduce, perhaps using Postman. Perhaps the confusion is in your definition of “acknowledge the product”. Are you calling a specific Google API, passing the user context and product info to ack the product from the server that changes the users’ product status as seen on Google Play? Method: purchases.products.acknowledge  |  Google Play Developer API  |  Google for Developers Keep in mind this API is deprecated, developerPayload is no longer supported in the Google Billing Library v3

Have you really read my post?
I wrote you, that this API is up to date.
And here is a fresh proof from Google team: https://issuetracker.google.com/u/0/issues/184760924
There is no problem with Google, or with my server, there is only problem with Unity IAP.
Why don’t you want to test and fix this critical bug?

1 Like

We will check

Thank you.
It is not safe to give a player items on the server without acknowledge.
For example:
Player buys gems. We give him gems on server and don’t acknowledge. Player close the game in pending status. Player changes Google account on Google play and opens a game. The player will have gems, but after 3 days money will be returned to his card automatically.
Player has gems, we have no money.
And it is not the only security problem.

If the user changes the Google account, how do they have gems? This is a consumable, the new user won’t see ProcessPurchase even if the product is in Pending. The original user, yes.

The user will have gems, because gems are stored on server. And server authorization may be not Google sign-in. It may be Facebook sign-in or email or phone number or something like this.

1 Like

Unity IAP is specific to the user signed into Google Play (Play Store) on the device. They second account would not see a ProcessPurchase. Unless you mean the UserA allows UserB to play the game without changing the phone profile account, and then they sign in as User A using Facebook, separate from the Google Play user ?

Yes. It is right. So I cannot give player an item on server for online game without acknowledge, because cheater user can change account.