How to identify that a user changed subscription in manage->setting? - ios

We support subscriptions in our apps and now users can change the subscription from the settings->manage subscriptions button on their ios devices.
How can we find out about these kind of changes in the app?
I was expecting to see a transaction on this change in the SKPaymentQueue or see indication for it when validating the receipt but I could not find anything when I changed from one subscription level to another (in the same subscription group).
Apple documentation on the storeKit (https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW6) mention cancellation but not subscription change.
How can the application (client side or server side) can be notified when a user changed his subscription?

By Validating Receipts With the App Store on monthly periodically basis just before user plan going to renew, you can check in Product Identifier
The product identifier of the item that was purchased.
ASN.1 Field Type 1702
ASN.1 Field Value UTF8STRING
JSON Field Name product_id
JSON Field Value string
This value corresponds to the productIdentifier property of the
SKPayment object stored in the transaction’s payment property.

Related

What the server-to-server responseBody looks like?

What the server-to-server responseBody looks like and how should i know if a user cancelled subscription or refunded?
I have seen this doc: https://developer.apple.com/documentation/appstoreservernotifications/responsebody, but still confused.I have not seen a field like cacellation_date.
Should i parse the latest_receipt_info, and then if user cacel subscription, there will be cacellation_data and cacallataion_intent?
The cancellation fields are only for the case that the Apple Support cancelled the subscription for a customer. In that case you get the cancellation_date_ms field in the server-to-server response.
cancellation_date_ms
The time and date that Apple customer support canceled a transaction or the time and date the user upgraded an auto-renewable subscription.
more details here.
cancellation_date is the corresponding field in the receipt itself.
Note: cancellation_date and cancellation_date_ms both only exist in the production environment.
To check if a user cancelled your subscription, you would use expiration_intent (The reason a subscription expired).
You can use this value to:
Decide whether to survey the subscribers who have opted in to an account on your system or show alternative subscription products within the same group, if the value is “1”.
Decide whether to show the same or alternative subscription products, if the value is “2”, since the user did not actively make the choice to unsubscribe.
Decide whether to present a subscription offer to win back the user if the value is "1".
more details here

In what scenarios is SKPaymentTransaction.transactionIdentifier the same as the validated receipt's transaction_id?

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.

Apple In-app purchase transaction_id of one purchase changes sometimes

Once I get a receipt from client and validate it by apple server, then I got a transaction id of the new purchase (it's an auto-subscription purchase) in this receipt. After a few days , I get a new receipt from the same client and validate it , strange things happen : the transaction id of that old purchase changes.
I compare the data of this purchase in the old receipt with the data in the new receipt , the only thing changes is the transaction_id field ,the original_transaction_id, purchase_date, expires_date, web_order_line_item_id and other fields are exactly same.
Than I check the database, I found about 1% transaction records have the same situation. And there is a trait, Most of their transaction id were increased or decreased by 1-2 .
I used to think the transaction id is the identifier of a purchase. Does anyone meet the same problem or know the reason?
Yes we see this happen as well. We see this triggered by 'Restore Purchase' button clicks.
If your 'Restore Purchase' button uses the restoreCompletedTransactions API then this will cause your transaction ID's to change. We have confirmed that this with Apple developer support.
Apparently you can call SKReceiptRefreshRequest instead which will just grab the latest receipt instead of replaying all of the transactions. It is my understanding that this will not cause the transaction ids to change.
We have, anecdotally, witnessed that the web_order_line_item_id values do not change across calls to restoreCompletedTransactions. However we only received an ambiguous, at best, response from Apple developer support when we asked for confirmation:
In regards to the web_order_line_item_id field, the value will change on every subsequent renewal.
You can use this, as long as you continue to store the new value as the renewal subscription events come in.
We take this to mean that the web_order_line_item_id is unique per renewal-purchase. Which neither confirms nor denies that it remains constant across calls to restoreCompletedTransactions
Additionally, I found this conference recording on Apple/Google/Amazon recurring billing very helpful (though, not for this particular case):
Rosa Gutierrez - The recurring nightmare. Implementing cross platform in-app subscription purchases
Based on latest Apple developer documentation,
web_order_line_item_id - A unique identifier for purchase events across devices, including subscription-renewal events. This value is the primary key for identifying subscription purchases.
transaction_id - 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.

iTunes: Associate transaction_id with an email receipt from a user

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?

ios auto renewal subscription and user in our service

In our service, each user has a username (email), password and a unique identifier. How can I link any purchases through Apples' auto renewal subscription to that user?
Is there any field that renders an Apple user as unique?
I don't want to link it to the device, because the user can run the app from many devices, so I want a unique identifier for the user.
Apple does not provide you a unique identifier for an Apple user or Apple ID (probably to help protect the users privacy). What I was doing was using their first Auto-Renewing receipt as their unique identifier. So you should be able to use the original_transaction_id in your receipt verifications. When you verify a receipt with Apple's servers, the response should include the transaction id of the original auto-renewing subscription that that user purchased from you regardless of which device they were on. And I've found that even if a subscription lapses and then starts again, there will always be the one original auto-renewing transaction that is referenced.
It's a bit of a trick but it seems to work.
Alternatively, you could also use an iCloud key-value store to store a unique ID. That ID will be the same on all a user's devices, but they have to have iCloud turned on on all their devices. And technically they could be using different accounts for iCloud than they're using to make purchases so this isn't perfect.

Resources