Apple In-app purchase transaction_id of one purchase changes sometimes
Asked Answered
A

2

24

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?

Accusal answered 18/2, 2017 at 8:31 Comment(2)
I am facing the same issue now and am interested in knowing how did you address the problem?Nominalism
Since I can't rely on transaction_id or web_order_line_item_id just now, I consider a purchase with new transaction_id and new web_order_line_item_id as a new purchase.Accusal
L
19

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

Legislator answered 8/3, 2017 at 22:32 Comment(5)
Thanks for the answer. Eventually, did you achieve uniqueness for each transaction using web_order_line_item_id?Nominalism
@Nominalism I am still not 100% sure that web_order_line_item_id is globally unique. We switched to using de-duped our records and started using SKReceiptRefreshRequest instead.Legislator
Just now we tested the Restore Purchase feature in our app, while it worked as expected, it didn't change any transaction identifier in the receipt.Nominalism
@Sriram, yeah, we noticed the same thing too. While it did not always change the transaction IDs, it is happening some of the times. The documentation says that it "deliver[s] a new transaction for each previously completed transaction that can be restored". I'm not sure what circumstances and/or conditions cause the transaction id to change. One thing you could test, which we did not, is calling restoreCompletedTransactions from a completely different device from the one that performed the purchase.Legislator
thank you guys for nice notice, original_transaction_id wouldn't be change anyway am i right?Xeniaxeno
B
9

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:

  1. 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.
  2. 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.
Bigener answered 8/10, 2020 at 13:56 Comment(2)
So how'd you go about renewable-subcription bought by userA -> who then deletes the app / time passes / subscription renews automatically -> now userB logs in with different account (but still same iTunes account) and restores purchases -> what ID should be persisted on server and what should it be compared when userB restores purchases? ( in this case we have to figure out subscription actually belongs to userA and userB should not be able to benefit from it).Sacksen
@PawelKlapuch I use App Store Server Notifications to keep track of subscription renewal event. So my database has all subscription renewal info, it does not matter if userA has deleted the app or not. UserB will only able to restore purchase if he use the same iTunes account and the subscription is still active. So when the userB restore purchase, I will check if that subscription already exist in database using web_order_line_item_id since it is an unique identifier. If yes, then inform userB the iTunes account has an active subscription on another app account.Bigener

© 2022 - 2024 — McMap. All rights reserved.