7
votes

I am working on an application which makes use of Google Play In-app Billing V3 to sell an item which valid for a certain period of time. After a user makes a purchase, I send the purchase data to our server and immediately consume it, if successful. The server then grants access to the extra service for this particular user until the period ends. Note: I am not using in-app subscriptions.

I am testing purchases with test users in the sandbox mode where payment is not taken. Most of them are successful and this flow works fine. However, sometimes, my purchases are cancelled by Google immediately. In the order history in my Google Checkout account, I see the line:

"For your protection, Google cancelled this order. The transaction was considered fraudulent.".

Even if this happens, I see that I receive a "purchaseState": 0 in the purchase data, indicating a success. Also, trying to consume this product also results in success (calling IInAppBillingService.consumePurchase(version, package, token) returns 0). Querying my inventory at a later time shows that I have no purchases (and therefore no refunds/cancels) and I am able to freely purchase the same item again. This is the same behavior as in the normal, uncancelled state.

  1. Does Google often cancel orders in the same way, outside of the test sandbox?
  2. Can items which were successfully purchased and consumed still be cancelled (i.e. money refunded) for reasons outside of the control of the developer?
  3. Is it possible to know about cancellations for products which have already been consumed?
2

2 Answers

1
votes

Does Google often cancel orders in the same way, outside of the test sandbox?

Google has a fraud detection system which helps to identify unreliable payment. For instance if someone uses a stolen credit card or same credit card is used by multiple accounts, etc. In this case payment transaction will stop even before it starts (before a payment provider is contacted) with the message in your question. In May this fraud detection system was not able to reliably detect test accounts, that is why you could see this message. Nowadays it is slightly better. In real life this happens very rare.

Can items which were successfully purchased and consumed still be cancelled (i.e. money refunded) for reasons outside of the control of the developer?

This is a tricky question, because what gets cancelled is not an item, but rather a payment transaction associated with this item. Theoretically, a transaction can be cancelled also later in time, but there must be a good reason for that. Same example with a stolen credit card can be valid here. In the real life I have never seen it before.

Is it possible to know about cancellations for products which have already been consumed?

Although I never tried it myself, I don't believe a consumed product can be cancelled. As I said, an associated payment transaction might be cancelled, but not a consumed product. It is because a consumed product can be sold again and there is no connection to a payment yet. If product is not consumed, if will be put into cancelled state, if a payment transaction assigned to it gets cancelled.

Hope this helps.

0
votes

I'm setting up the same kind of application.
The user can purchase an item, it will be tracked on my server and, finally consumed, so the user can purchase again the same item.

I'm keeping track of all the informations about the purchase, and I've tried to cancel an already consumed order. I can confirm you that the status of the order is going to change (after 10 mins more or less, you will receive the email about the cancellation as well).

Calling this url of the PurchaseAPI with your productId and purchaseToken will return the purchase information:

https://www.googleapis.com/androidpublisher/v2/applications/<app.package.name>/purchases/products/<productId>/tokens/<purchaseToken>?access_token=<myToken>

The first time you will get a similar response:

{
  "kind": "androidpublisher#productPurchase",
  "purchaseTimeMillis": "1458047931024",
  "purchaseState": 0,
  "consumptionState": 1,
  "developerPayload": "mypurchasetoken"
}

and after cancellation the purchaseState is going to change:

{
  "kind": "androidpublisher#productPurchase",
  "purchaseTimeMillis": "1458047931024",
  "purchaseState": 1,
  "consumptionState": 1,
  "developerPayload": "mypurchasetoken"
}

This is the same GET that I do the first time for the product verification.
It's probably wise to set up a periodic check of the state of the purchased items and, in case of cancellation, update the purchase on the server.