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
, andproduct_id
for each transaction, as a best practice to store transaction records for each customer. App Store generates a new value fortransaction_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 theoriginal_transaction_id
. For subscriptions, it indicates the first subscription purchase. For a restore or renewal, thetransaction_id
does not match theoriginal_transaction_id
. If a user restores or renews the same purchase multiple times, each restore or renewal has a differenttransaction_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.