When building In App Purchases into an iOS app, Apple gives you access to a receipt that you can send to your server to view all In App Purchase transactions for that given iTunes user related to your application.
If in my application I require users to login or create an account through my system before making a purchase, how can I guarantee that iTunes receipt will not be duplicated?
For example, if a user makes a purchase, the application sends the user ID, and iTunes receipt to my server. The server then stores that receipt along with the user ID in a database. The next time the server wants to check the users purchases we can retrieve all the receipts for that given user ID out of the database and run checks on it.
But if the user logs out and logs in as a different user and makes another purchase the receipt will be sent to the server again, with a different user ID. Effectively, allowing 1 purchase to be used on unlimited user accounts.
Due to the fact that the receipts change over time (auto renewing subscriptions, etc), I don't think it's safe to rely on the receipt being the same every time it's sent to my server and using the receipt data as a unique identifier.
I also considered storing the original_transaction_id for one of the transactions, but I don't think that would work since an application might have multiple non-consumable items, or multiple subscriptions, therefor there might be multiple completely valid original_transaction_id's in one receipt. So it doesn't really associate that receipt, but just the transaction.
Ideally, I'd like a system where when a user logs out, and logs in (as a different user or same), the application will send the receipt to the server, and dissociate any of the same receipts for all existing users, and link this new receipt to the user that logged in. Problem is, it doesn't look like there is any type of unique identifier for a given receipt that I can use to check for duplicate receipts in my system.
What is the best way to detect duplicate receipts sent to my server (so I can dissociate the old receipts accordingly)?
PS. I think this system is most important for subscriptions, and non-consumable items. For consumable items it will always have to be linked to 1 specific user, and I can just store the transaction_id and original_transaction_id for that consumable item to ensure it doesn't get duplicated.
Related
Im working on an app which will support subscribing to a premium version.
Whenever a user buys a subscription I can verify the receipt on my backend, persist important data and grant entitlement which is good.
However, when a user buys the subscription for the first time I rely on the Firebase User ID in order to query my DB.
When I receive App Store server notifications I query by the original_transaction_id.
Now comes the problem, I do not know whether a subscription can be bought initially outside of my app. (I only sell them in-app, but am not sure if apple provides a way to buy them outside of the app.).
If it is possible it would cause a problem.
Hello I am currently trying to take advantage of the Subscription Status URL that iTunes connect gives you to get updates on a auto renewable in app subscription.
I have my endpoint up and running, and I am getting all the receipt info I need and the status of the update, however I have no current way of tying this update back to a specific user of my application.
For example, every user of my app has a UUID, and in a perfect world I would somehow like to tell Apple during a purchase which user uuid purchased this subscription and then get that UUID back in the POST request from the Subscription Status URL.
Is this possible?
You have identified what I consider to be one of the biggest flaws in StoreKit, that the receipt does not contain a way to identify the user (iTunes account in this case).
The way around this is: When your users make a purchase and your app processes a transaction, you need to post the transaction identifier (and probably the receipt data) to your backend and associate it with your user's backend record. Then when you get a push from Apple, you can look up the user it relates to by transaction id.
This is not an ideal solution, since different app users can be sharing a receipt via the same iTunes account and other edge cases like that, buts it is a good as you can do with the way app receipts work.
here's my straightforward question:
is it allowed for my iOS application to force users to log into my custom account management system, so I can link them to my backend when they want to purchase a non-renewing subscription?
Here's the backstory:
I have a non-renewing subscription. For a good amount of users I can see that the Apple receipt does not contain information about this subscription; the in_app array is empty. This is correct according to the API:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
The in-app purchase receipt for a consumable product or non-renewing subscription is added to the receipt when the purchase is made. It is kept in the receipt until your app finishes that transaction. After that point, it is removed from the receipt the next time the receipt is updated—for example, when the user makes another purchase or if your app explicitly refreshes the receipt
For some users, I can still see the purchase in the receipt, but let's consider that a bug from Apple and follow their API documentation to the letter.
(More on why this is a bug here https://forums.developer.apple.com/thread/22345)
In order to restore the user's purchase, I'd need something to identify him with. I could create a unique token, store that on the iCloud keychain and use that across the devices to detect the purchase belongs to that Apple account, but since my application supports account creation, I'd rather just use that mechanism. Else I'm using two different methods of purchase detection side by side: iCloud keychain token or a user account.
Thing is, I'm not sure I am allowed to force users to make an account before making a purchase. Is this something Apple would reject the app submission for with a message like "Your users must be able to buy stuff without going through your lengthy account registration process" ?
From Apple :
Non-renewable subscriptions. Subscriptions that don’t involve
delivering episodic content. Examples include access to a database of
historic photos or a collection of flight maps. It’s your app’s
responsibility to make the subscription available on all of the user’s
devices and to let users restore the purchase. This product type is
often used when your users already have an account on your server that
you can use to identify them when restoring content. Expiration and
the duration of the subscription are also left to your app (or your
server) to implement and enforce.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
So its your app's responsibility to check that user has valid subscription or its over and let them purchase it again !
For this you will ask user to first make account or login into app so by this way you can track their subscriptions.
In my app I have items to show just for users that are pays for subscription. User can log to app by e-mail and password and can logout and on same device can log different user.
My problem is that Apple Id in phone is still same. So when different user logged in he could restore purchase even that he didn't pay anything.
So my question is how can I fix it? How can I connect Apple account to my custom account? Or at least somehow when trying to restore IAP check that this Apple account already have this subscription but different user was logged in. How other apps do this? Thanks
Edit:
I want to use Auto-renewing subscription in my app and I just don't know how to connect it to my custom account system.
When a user makes an IAP, you will not know the Apple Id used to make the purchase. What you will know, however, is the transaction id for the purchase. What you will want to do store the transaction id of the original purchase with your custom account.
When a user restores, you will determine if the SKPaymentTransaction's originalTransaction's transactionIdentifier matches the custom account. If not, then you can assume this is a different user. You can read more about that here:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html
Note that the receipt contains a field called the original transaction id. This is what you would use for subscriptions to track the original transaction id. This is because each time you auto renew, a new transaction id will be generated for the auto renew. The receipt will actually contain all the purchases.
On your server, you would want to save the original transaction id and potentially the receipt. Essentially the more metadata your store around this, the better off you will be if you have to do any form of double checking transactions.
I know this is a valid scenario, that the iTunes receipt for in-app purchase might contain multiple products.
Just wanted to confirm when can this happen or how do I reciprocate this behaviour for a sandbox id.
Currently its happening on only one of my sandbox user id's. I don't know why but its not happening on any of the other or any new sandbox user id's I created. All of the other id's are receiving a single product per receipt.
This is critical to know because the server side needs to parse this info correctly, so all I need to know is when can this scenario of receiving multiple products per receipt re-occur ?
Thanks