Detect if a user refunded a 'consumable' in app purchase item (Apple app store in app purchase system) - ios

I read so far online that the only way to detect if a user cancelled an in app purchase is by using the receipt data that I get from the user's iPhone and check if the cancellation_date exists in there for that item, but as far as I know, this field is only to be found on auto-renewable subscription items.
(At least to what I read online on every post I found that talks about in app purchase, no mention to consumables at all.)
Because they are always stored in the receipt data, while consumable items, are stored in the receipt data until the app itself finishes the transaction, once thats done, the purchase transaction for that item is gone forever from the receipt data after the finish process on the iPhone.
So my question is, if a user requested to cancel an in app purchase from Apple, which is a consumable item, do I also get back that same item transaction in the receipt data WITH the cancellation_date field in it?
I've never seen anyone confirm this.
It would be nice if someone can provide a receipt-data base64 string with cancellation_date example in it (if that's legal to do tho).

https://developer.apple.com/documentation/storekit/in-app_purchase/handling_refund_notifications
Apple has provided a solution finally in 2020!!

A year ago I had the same question as you and I have found this thread where author said that Apple has not added a way to detect canceled purchases. I'm still living with that as it is.
The best way to know it is contacting Apple technical support, each account has 2 request/year, so I recommend you to write there.
Hope you will find the answer and tell us about the result.

Related

IAP cracks that seem to have valid receipts

We have a successful app on the iOS app store with in-app purchases. Every time a purchase is completed we send the receipt to our server, our server than checks the receipt with Apple's servers and logs apple's response(including whether the purchase was valid and that they come from our app in that same time and date).
We have quite a few users who use iap cracks that send us receipts that apple says are invalid. However we started now to see cheaters that have receipts that apple replies that are VALID. What is strange in these cheats, that when such a cheater user purchases in our app, he usually purchases all of the purchases with the exact same receipt.
Have you heard of such a way to 'fool' apple receipt validation?(to generate receipts that apple will say they are from our app in the time of the 'purchase')
Is there something we can do to find those cheaters in their 1st purchase (for the next purchases we can simply check times of the next receipts or make sure that our receipts are unique)
Thanks!
Is there something we can do to find those cheaters in their 1st purchase
Actually, if this is the same hack I've seen discussed as a proof of concept recently, the first purchase is legitimate. The "innovation" is in decoding that legitimate receipt and rejigging its IAP ID with a different one while the receipt overall still appears valid. So simply avoiding the duplicates is enough. Didn't think that one was anywhere near production-ready though, so this might be something different.
We also faced similar issue while developing a game of iOS app store where business model was based on In App Purchase only.
Initially we used to check with Apple Servers for the receipts directly from the device. But some hacker has created a hack for the users where they can install the DNS server certificate on their device which spoofs the response from Apple.
The way to do this is let web server check for the receipts from Apple directly with some kind of hashing or md5 check to make sure the response if from Apple.
here is a link which have a detailed information on this https://www.objc.io/issues/17-security/receipt-validation/
Hope this helps.

How to track In-App Refund in ios app [duplicate]

Situation:
- User makes an IAP and is awarded some content, we store the users device id to ensure they can access this content whenever they want.
- User decided they do not like the content, so they call Apple and get a refund.
- User can still access the content, even though they have been refunded for their IAP
Problem:
We don't want the user to be able to access this content anymore. This could become a loophole that they would take advantage of. (unlock content, then get refunded and keep their access to said content)
Question:
Is there any way for us to check if a user has been refunded for an IAP with either their transactionId, transactionReceipt, or any other information we may have?
For Reference, I've read the StoreKitGuide, it did not mention this case.
No. There is no way to revoke access to content if they have been refunded. I believe this is by design. It is the same with App Store refunds; if someone buys an app and then asks Apple for a refund, Apple does not stop the user from continuing to use the app.
No. you cannot stop user to access. Apple does not stop user to use that feature after refund
Below a recent answer from the overbearing Apple!!!
At April 11
Hello Joe,
Thanks for your quick reply at first.
I think there were some misunderstandings. We understand that you must protect the user information. And we do not require any user info. We do not require any user's information---- iTunes account, User Name, email address and other information about himself/herself.
We require only one data----- transaction id (named "transactionIdentify" in your code), for example "1000000033409668" (this transaction id is a record at March 13).
A user buys a product from IAP, you will generate a "transaction id" and send it to us. This transaction id is stored in our database then. Now he/she gets refunds from you, so please send the transaction id to us. Let us know which one in the game canceled the IAP.
When a refund occurs, we think you should provide the transaction id to us. With these data, we could make a more fair service for all players. If you do not do it, more and more players will use your refund mechanism to get game items without real payment. You and we will lose money then. We think it is very important.
Regards,
Baibo
At April 12
Hello Baibo,
Thank you for following up with me regarding the refund transaction data.
We will not be able to provide you with the refund transaction data you have requested as it is not a feature or benefit provided to you per the contracts you have agreed to.
To view your paid applications contract and review your membership benefits, please access the contracts, tax and banking module within iTunes Connect:
http://itunesconnect.apple.com
If you are not happy with large refunds, you may want to consider adjusting the price of your in-app purchases as we will not be able to provide you with the refund transaction data in the future.
According to an answer one of my users received from Apple, refunding an app means they will no longer receive updates to the app, but doesn't remove the app from the device. IAP appears to work the same.
I am wondering if there is not a way by using restoreCompletedTransactions to check for the iAP purchase, but this would pop up a request for the user's iTunes password, so its use is limited.

In app purchase query

I am working on in app purchase which works fine but I want to know that user have purchased product or not at the launching time of application.
How should I know this.
If anybody knows please help.
Thanks in advance.
You can store a "receipt" in the user defaults (NSUserDefaults) then check if the receipt exists when the app is launched.
HOWEVER plainly using NSUserDefaults is prone to hacking so you can use a secure version of user defaults from here.
another solution (and the recommended one if done correctly) will be to store receipts on a server and read available receipts when the app launches. (Note though that if the user has turned device data off you won't be able to read them).
It would be best to get the user's purchase receipt and check all the products they have purchased.
You can follow the guide here to see how you can validate receipts locally.
This document explains the structure of the receipt - the in-app purchase fields have the product identifiers which can be used to find out which IAPs the user has access to.

Refund the previously purchased non-renewing subscription, not the current one. Possible?

I'm implementing an iOS app with non-renewing subscription. Not much relevant information was available online; so I seek your guidance.
A use case which worries me the most is when a user purchased the subscription once and then immediately after purchase it again to extend the duration of service (see such scenario here). What if that user were to refund the first purchase, leaving the second one intact? Is this even possible in practice, or am I just too paranoid?
Assuming the above case is possible, my app will run into a problem because, as far as I know, verifyReceipt only returns the latest, good receipt (watch Managing Subscriptions with In-App Purchase in WWDC'12).
I find nowhere Apple provides relevant information about refunding policies.
(Auto-renewable subscription seems to rule out this case as a renewing action is taken care by iTunes automagically and it seems not possible to extend this type of subscription until iTunes allows it.)
verifyReceipt will not only return the latest good receipt, it will also tell you if the receipt you submitted for verification is good. So if you're concerned that a user may have cancelled* a transaction, then submit every receipt you're questioning.
*But what do you mean by "cancel" the first purchase? Do you mean when they tap "cancel" instead of "buy?" Well then the transaction won't go through and you won't even get a receipt.
Or do you mean when they request a refund? I don't know any other way they can cancel a purchase.
Edit:
If you're referring to refunds, there's no way for a developer to tell if a user has been issued a refund. The assumption is that Apple expects you to continue to deliver services to that user regardless of the fact that they received a refund. Your receipts will probably all verify correctly regardless of the status of a refund.

How does Apple notify iOS apps of refunds of in-app purchases (IAP)?

I have Apple iOS IAP successfully implemented in my app and tested in the sandbox. Works great.
I'm concerned that users could buy something with IAP, download it into my app, then complain to Apple and get a refund. There's no obvious way that refunds are reported to my app. Are they simply left out of the list of products I receive during a "restore" operation? Is there some undocumented transaction type that will asynchronously show up in my SKPaymentTransactionObserver when a refund occurs?
Right now I'm operating on the assumption that I need to delete the user's IAP transactions before doing a restore, and that anything refunded will just not be in the list of restored transactions. Is this the right way to do it? Is there any way to test this in the sandbox?
Has anyone seen refunds in a production environment and can explain how they work?
Update June 24, 2020:
At WWDC 2020, a new notification was introduced that informs you of refunds: https://developer.apple.com/documentation/storekit/in-app_purchase/handling_refund_notifications
Original answer:
I received a response from Apple Developer Relations today (Dec 6, 2018):
Hello Johannes,
In response to your question, unfortunately, there is no supported means to detect that the user has contacted Apple Care and received a refund for the In-App Purchase of a consumable item. The only option which I can refer you to is to submit an API enhancement request for an API to be made available for an app to detect that a refund was provided to a user of an In-App Purchase. Currently, this support is realistically only available to apps which offer auto-renewable subscription In-App Purchase.
You can submit the enhancement request using the Apple Developer Bug Report web page - http//bugreport.apple.com
As this is an enhancement request type issue, I'm going to arrange for this incident to be unbilled from your account for use on a future issue.
So there we have it.
The in-app purchasing guide discusses the concept of "cancellation" of subscriptions. This is the only place I've seen discussing the subject.
Further details about the cancellation date field can also be found in the App Store receipt validation documentation.
cancellation_date
After decoding a receipt, you can get the cancellation date which will tell you the following:
For a transaction that was canceled by Apple customer support, the time and date of the cancellation.
The strategy is:
You save the latest_receipt ("MIIUJgYJKoZIhvc..." base64) field in your DB, associated with the user account.
Every day you query apple to validate all the receipts, by sending them the base64 receipt from saved latest_receipt field.
In the receipt you check if there is a cancellation_date field. If you find it, treat it according to documentation:
Treat a canceled receipt the same as if no purchase had ever been made.
Same way you also checking subscription renewals (check expires_date_ms field).
Refunds are given, but your app gets no notification of them at all. Whether it's an In-App Purchase, an app download or any other iTunes content, the user can still use the content even if they have asked for a refund.
In iOS 14 a new method is added to the SKPaymentTransactionObserver protocol that is called when the user is no longer entitled to one or more in-app purchases ๐Ÿ‘‰ https://developer.apple.com/documentation/storekit/skpaymenttransactionobserver/3564804-paymentqueue
Although the documentation doesnโ€™t tell in which situation this method is called, Apple does tell this in this WWDC2020 video at 26:55 ๐Ÿ‘‰ https://developer.apple.com/videos/play/wwdc2020/10661/
According to latest documentation, server to server notification with type CANCEL is now handling cancel scenario by Apple customer support.
Starting October 21, 2021, App Store Server Notification Version 2 became available and the notificationType in the notification payload will be returned with REFUND when the App Store refund process is completed.
See below for more information.
https://developer.apple.com/documentation/appstoreservernotifications/app_store_server_notifications_v2

Resources