From time to time we receive user support requests where the user complains that they did not receive their item in our game.
In our database we are logging the transaction_id returned by the iTunes API whenever we issue a purchase. So in theory we can verify if a user has received their item or not, based on the field transaction_id.
However the transaction_id seems to be pretty useless. Whenever users send us a copy of the email receipt by Apple or send us a screenshot from their iTunes purchase history, they include order number or document number, but none of those matching the format of the transaction ids.
How can we associate any given receipt email from Apple with transaction_ids in our database, so our user support team can verify if a purchase has already been handled or not?
Related
The documentation for SKPaymentTransaction.transactionIdentifier notes:
This value has the same format as the transaction’s transaction_id in
the receipt; however, the values may not be the same.
And the documentation for transaction_id notes:
This value has the same format as the transaction’s
transactionIdentifier property; however, the values may not be the
same.
You can use this value to:
• Manage subscribers in your account
database. Store the transaction_id, original_transaction_id, and
product_id for each transaction, as a best practice to store
transaction records for each customer. App Store generates a new value
for transaction_id every time the subscription automatically renews or
is restored on a new device.
• Differentiate a purchase transaction from
a restore or a renewal transaction. In a purchase transaction, the
transaction_id always matches the original_transaction_id. For
subscriptions, it indicates the first subscription purchase. For a
restore or renewal, the transaction_id does not match the
original_transaction_id. If a user restores or renews the same
purchase multiple times, each restore or renewal has a different
transaction_id.
Also will note the Receipt Validation Programming Guide (from the Documentation Archive) states under Transaction Identifier:
This value corresponds to the transaction’s transactionIdentifier
property.
With that noted, my question is: when is the SKPaymentTransaction.transactionIdentifier the same value as the validated receipt's transaction_id, or when isn't it?
In our app we only work with consumable in-app purchases, no subscriptions. In this scenario, are these two values the same? I ask because I need to be able to record the purchase server-side along with information about the user who purchased it. See below for an explanation of the process and problem it presents.
Let’s say a user purchases a consumable product and the request to record that transaction fails because our server is down for example, so we do not call finishTransaction:. Now let’s say that person logs out and logs into a different user account and purchases another consumable product and again we fail to record it. There are now two consumable products in the receipt. When they launch the app next paymentQueue(_:updatedTransactions:) is called with two items in the transactions array to inform us there’s purchased transactions we need to finish. We need to submit the receipt to our server to record the transactions but we also need to send some additional info along with each transaction such as the user id who purchased it. This means I need to persist this info on disk with an associated transactionIdentifier so I can get that data later. I can send an array of user ids and the receipt to the server. But how would the backend know which transaction in the receipt matches which user id in the array? I don’t believe the in_app array is guaranteed to be sorted in any particular way and may not match the order of the transactions array provided to paymentQueue(_:updatedTransactions:). So when there’s multiple transactions to be recorded, how can we properly link them so the purchase is applied to the correct user account server-side? In this scenario, is the transactionIdentifier available in-app guaranteed to be the same as the transaction_id in the validated receipt?
In testing we've determined the transactionIdentifier is the same value as the transaction's transaction_id in the validated receipt for consumable purchases.
However, we are reluctant to rely on that being the case due to the note in the documentation stating it may not be the same value. So we put a fallback in place to uniquely identify a transaction using a combination of the transaction.payment.productIdentifier and the transaction.transactionDate, which is documented to correspond to the original_purchase_date_ms in the receipt. This allows the backend to find the correct transaction in the receipt for the information the app submitted.
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.
I'm using auto recurring subscriptions in my app in my app,I need to change the subscription status if recurring fails from iOS.
I am following this documentation, but there are a few things that are still not clear to me:
What if my server missed the post data from iOS
How do I know if the subscription got renewed
How do I link my app user memberId (unique id) to the transaction
What is the difference between latest_receipt form iOS post data(server to server notification) and bundle receipt url after purchase.
Here are the steps I take the user to subscribe:
Ask the user to sign in. If they don't sign in they can't subscribe.
Send the app receipt to my server and store it there. If this fails they can't subscribe. This need this to validate get the latest_receipt info from the server at any time.
The user subscribes through iTunes.
Validate their receipt with the app store and check the latest_receipt to make sure they are subscribed. (This is done server side)
Repeat step 4 periodically to make sure they are still subscribed
So to answer your questions:
What if my server missed the post data from iOS?
Since I get the app receipt from the user before they subscribe I can check the with itunes directly from my sever any time and get the status of their subscription.
How do I know if the subscription got renewed?
Since you have the user receipt on your server, you can use it to get the latest receipt from apple and check the current status of the subscription. Here is how you do it Validating Receipts With the App Store
How do I link my app user memberId (unique id) to the transaction?
You could use the "Original Transaction Identifier" from the receipt as a unique id. This value is the same for all receipts that have been generated for a specific subscription
What is the difference between latest_receipt form iOS post
data(server to server notification) and bundle receipt url after
purchase?
When you send a receipt to the app store to be validated, it will return a JSON representation of the receipt that was send, this can be found in the "receipt" field. If your receipt contains subscriptions you will get "latest_receipt" and "latest_receipt_info" fields. These fields are useful when checking whether an auto-renewable subscription is currently active. If the bundle receipt is up to date then the "receipt" and "latest_receipt" will be the same.
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 understand that If a user buy something using in app purchase, it should reflect in all the devices owned by the user ( based on logged in apple id ).
But in my case I need to handle it with "our own username and not apple id". That is if user logged in to our application in multiple device, We need to handle subscription all our own.
Just to clarify, even if user logged in to two devices with same apple id but different user in our application, only the username who actually bought our subscription should get the extended access.
I believed that non-renewable subscription is what We need, but on reading a bit, I think such a subscription should reflect in all devices registered by same apple id.
So it would be great if someone could help me to select which kind of in app purchase should i choose for this scenario.
Any help appreciated. Thanks.
The kind of in app purchase for this would be preferable is non consumable. In this case user don't have to buy the product again and again. Regarding your question with your own username you can maintain the record of purchase for single user in your local server. For that what you can do is while verifying the transaction receipt from your local server which you will get on every successful transaction from apple in app purchase server. For verifying the receipt you have to send the receipt to you local server in base64 encoded format then your local server will connect to the apple server you local server will verify the receipt while sending the receipt to your local server send the session id of the user to your local server if the verification of the receipt is successful then you local server will store the purchase information in local data base. If user will login in the second device also you local server will know that this user have purchase this many item and you can sink the data in all the device in which user have logged in.