Consumable in app purchases validation - ios8

We recently launched the app which has only consumable in-app purchases. We noticed lot of fake purchases - purchases with invalid receipts and also 'valid' receipts but the "in_app" array in the validation response from apple is empty array. I need to know how users are forming such a 'valid' receipts ? Is it the receipt of the app download and not of in-app purchase or what ? I am now putting the following check for validation. Extract "in_app" field in json response from Apple and if it is non-empty, then check the product_id matches or not. I need to know if this check is enough or their is a better fool proof check.

All apps have a receipt. Those apps that have purchased an IAP have an in_app field in their receipt. Your users are pushing a fake call into their updatedTransaction method and you are grabbing their receipt (sans IAP cause they made no purchase)and sending it to your server. Other users might swap some receipt from somewhere (e.g. one of 30 thieves makes a purchase and extracts that valid receipt and sends it to their 29 co-thieves). If they stick that receipt into their device and then push a call to updatedTransactions then your server will get their now-valid-but-duplicate receipt. Your server needs to check *** the date of the receipt and discover it is older than recent or, even better, older than the paymentRequest which you would need to co-send to your server. (it is better to decode on the device - much more secure)
*** you used to be able to check transaction_id for a duplicate transaction_id. Unfortunately you can no longer do that since a restoreCompletedTransaction returns the same transaction_id as the original purchase. I have told Apple about that and they ignored me.

Refer to this In-App Purchase FAQ My app validates its receipt with the App Store via paymentQueue:updatedTransactions: after a successful purchase. However, the returned receipt contains an empty in_app array rather than the expected products.
An empty in_app array indicates that the App Store has not recorded
any transactions for the user yet. It may be that the application
receipt has not yet been updated. When this happens, your app can
inform the user that the receipt does not appear current and ask
whether to refresh it.
Information about consumable products is added to the receipt when
they are paid for and remains in the receipt until you finish the
transaction. After you finish the transaction, this information is
removed the next time the receipt is updated. Thus resulting into an
empty in_app array if your app only sells consumable products.

Related

Android Google Play Subscription gets canceled after buying it

I have a react native app and using react-native-iap library to communicate with Apple/Google server to buy the subscriptions. The subscription got successful and it returns a transaction as well but when I try to use that receipt to validate in in-app-purchase library, it returns with cancelReason: 1. I don't know what's happening but as per the Google Play cancelReason:1 means, "Subscription was canceled by the system, for example because of a billing problem"
Below is the real purchase I tried with my app. I have added the amount to buy it from the prod app which uploaded on internal testing. This library isn't able to verify it. Even it's showing me as an active subscription on the Play store app in Manage Subscription.
If I try to restore purchase in my app, it would return a purchase but when I went to verify it from the in-app-purchase library, it doesn't validate. Don't know why.
Here is the receipt data I got from the react-native-iap library.
{"purchaseToken":"sdfdsfssfsd.AE-Jw-8fCifXt8xC1LzUDMhl2EyupYjgdGjmkpdHZH-j3-0YWE4UGa_jFlKTwodhLbKXCIWg","productId":"com.xyz.subscription","acknowledged":true,"orderId":"GPA.31-25-01-22058","purchaseTime":1620884406333,"packageName":"com.xyz","purchaseState":0,"autoRenewing":true,"subscription":true}
The response I got from the in-app-purchase library -
{"service":"google","status":0,"packageName":"com.xyz","productId":"com.xyz.subscription","purchaseToken":"sdfdsfssfsd.AE-Jw-8fCifXt8xC1LzUDMhl2EyupYjgdGjmkpdHZH-j3-0YWE4UGa_jFlKTwodhLbKXCIWg","startTimeMillis":"1620884406333","expiryTimeMillis":"1623562757349","autoRenewing":false,"priceCurrencyCode":"INR","priceAmountMicros":"79000000","countryCode":"IN","developerPayload":"","paymentState":1,"cancelReason":1,"orderId":"GPA.31-25-01-22058","acknowledgementState":1,"kind":"androidpublisher#subscriptionPurchase"}
if it got canceled as per the response, I didn't get any refund in my account.
Please help :(

Local receipt doesn't get updated after (automatically) renewing a subscription

I have an app that uses in-app purchases (IAP), specifically auto-renewable subscriptions.
Occasionally it seems that, when a subscription automatically get renewed, the local receipt doesn't get updated automatically. As a result, checking locally if an active subscription is available results false. Performing the same validation remotely (using Apple servers) returns true.
How and when is the local stored receipt updated or is this something that can only be triggered manually? If so, does this need to happen using SKReceiptRefreshRequest or SKPaymentQueue's restoreCompletedTransactions? Based on Apple's documentation the former seems to be the way to go:
A request to refresh the receipt, which represents the user's transactions with your app.
Unfortunately, this fails, perhaps because it thinks there's noting to update? However there is: as the local receipt is outdated as it doesn't contain the renewed subscription status.
I want to ensure I'm doing things correctly and this behavior (that again happens occasionally) is not something on Apple's end.
Thanks for any feedback.

Server side receipt validation for non-consumable products in iOS7 and transactionReceipt deprecation

I'm porting a working application from previous iOS's and am having trouble with the new in app purchase receipts.
The way we work now is to take the transactionReceipt property from the SKPaymentTransaction object and send it to the server for validation.
From what I could gather from other questions, it seems that the receipt is now held in one place, being :
[[NSBundle mainBundle] appStoreReceiptURL];
There are a few things I don't understand here :
Is there now one receipt for all of the purchased products?
If so, does this file grow and grow and grow?
If I want to send single receipts for single products to the server, how can I?
Is the only way to send the full file to the server all the time?
Very confused by this, any help would be greatly appreciated.
From what I've been able to gather via Apple's documentation.
1) There is one receipt for all purchased products. In order to perform server side validation you send the entire receipt to your server, which forwards it to Apple for verification. See this post on the Apple Developer Forums (starting around comment 13) https://devforums.apple.com/thread/193893?tstart=0
2) Non-consumables will remain in the receipt forever, so yes it will grow and grow. Consumables are removed lazily from the receipt once finished via a call to finishTransaction. See https://devforums.apple.com/message/876265#876265
3) The iOS6 way of looping through updatedTransactions and sending individual receipts to your server for validation seems at odds with the new iOS7 design. This post on the Apple Developer forums suggests you "Send the whole list of transactions to your server with the receipt. When the receipt is verified, deliver all of the products, and finish all of the transactions." https://devforums.apple.com/message/897870#897870
4) That really does seem to be the case.
If you believe the iOS7 documentation is lacking you can raise a bug report with Apple

Saving an IAP receipt

I would like to save in IAP receipt for non-consumables in my database. We have a two-step download mechanism for IAP restores.
Retrieve all transactions with the StoreKit mechanism which include the receipt.
Choose the transaction to restore at a later point in time from a list of all receipts (i.e. the products behind those receipts)
Is there any word regarding on how long the data can be treated as valid? What other drawbacks could I encounter by persisting the data?
There is no such a date when your receipt invalidates—you can always send it to Apple server and it will decode it to JSON for you.
At least, there is no such info anyway, so untill Apple will do such a thing in one way order, you can feel safe to store it.

In-App Billing subscription issues

With the release of the new subscription option from In-App Billing API we started a proof of concept of the service and we found a few issues. Has anyone else tried it and would have some answers for us? Here's the issues we have been facing so far:
1 – While testing the unsubscribe functionality, the Google Play interface displays a white page with an “Item not found” message and a retry button. Is it due to the fact the app is not yet published? If yes, how can we test this flow without publishing it first?
2 – Inter device synchronization. When making a subscription on one device, other devices tied to the same account did not receive a OnPurchaseStateChange event. Is it again due to the fact the app is not published? Or are subscriptions tied to a particular device and not to an account?
3 – On our Google merchant page, when we cancel a purchase, the device does not receive a notification telling the subscription has been cancelled. Is this a bug? As a workaround we are manually checking the current time and comparing with the expiration date to force a restore transactions call. At this point, we are able to see the subscription is no longer valid. Do you think this is an acceptable solution?
4 – When a subscription is made, two transactions show up on the Google Merchant page: a FAILED transaction with a value of $0 and a valid one with the value we charged. Is this the expected behavior? What’s the purpose of the $0 FAILED transaction?
If anyone has faced similar issues we would like to know. Maybe these could be bugs on Google's end or maybe we did not understand 100% how it is supposed to work.
Thanks in advance.
1.I had the same issue and after I published (and later unpublished) my app I could see the app page in the market,so you can publish and than unpublish.
2.I didn't check it with subscriptions ,but for managed item i didn't get purchaseStateChange on two different devices as expected.
3.I do get subscription expired after canceling one,but only after a while.
I didn't understood how you can get the expiration date ?
you only can get it with access to play developer api.
the restore transactions will give you same purchaseStateChange as you got when purchase the item.
*in the developer guide it is recommanded to use restore transactions only in first app use.
4.I have same issue,and i heard at least about 10 people with same 0$ charge.

Resources