Transaction id from device not in list returned from Apple

We have an app in production at the moment that offers recurring in-app purchases. Things are working well, except for a handful of users...


After the initial payment for a subscription is successful, we send the value of SKPaymentTransaction.transaction_id and the contents of Bundle.main.appStoreReceiptURL to our server for validation. We pass the receiptBlob to Apple's https://buy.itunes.apple.com/verifyReceipt API and in 99% of our cases, we get back a matching transaction_id, however, there are a bunch of cases where it returns a different identifier.


The values of the identifiers are always pretty close numerically (for example, 220000325892796 vs 220000325892855 - a diff of 59), but at the moment, we're using these values as part of our server-side receipt verification logic which brings us unstuck.


I can't reproduce using the sandbox environment at all. The closest I've come is (but not really):


  • User successfully purchases subscription
  • Network goes down so they can't notify/validate with our server
  • User attempts to purchase subscription again. This time they get a message from Apple saying they're already subscribed, however they do get allocated a new transaction identifier
  • Network comes back up and they send the *new* transaction id into our server.


The big difference between the above scenario and the one we're experiencing in production is that in the above case, the transaction_id is different to the original_transaction_id (which I can rationalise to myself), whereas in our production cases the transaction_id and original_transaction_id values are the same which imply that it is the original transaction.


I just don't understand how I can go from being given a transaction id on the device and then when retrieving the receipt detail from Apple's server I end up with different transaction identifiers.


Very puzzling... any thoughts would be much appreciated.


Cheers,

Craig

The transaction_Id field is in the IAP array in the receipt. It reflects the 'purchase' event that downloaded the renewal of what was purchased as the 'original_transaction_Id. It should match the transactionIdentifier of the transaction that records that renewal. But then there are three subsequent types of transactions that might result in a different 'transactionIdentifier' but that same transaction_Id - because they are reporting on the earlier transaction.


1) (I am not sure about this one) If a user has two devices and purchases on one and restoreCompletedTransaction on the other - then both devices get a transaction at renewal time. I am pretty sure that the two transactions will have different transactionIdentifiers but I do not know if they will have the same transaction_Id (or original_transaction_id) in the receipt.


2) If a user does a restoreCompletedTransaction they will certainly generate a new transactionIdentifier but get the old transaction_Id in the receipt.


3) a hack.

Thanks for the feedback. None of our users have reported that they're using multiple devices, but I will see if I can reproduce in your first scenario. I'm pretty sure it isn't being hacked - the users are calling our helpdesk to ask for help :-)


FYI, I raised a DTS in case there was something stupid we were doing in our code. Got good feedback, but the net effect was that (in theory) the transaction *should* be able to be used, but generally speaking we probably should be relying on the contents of the receipt to see what is current, rather than checking the transaction id. Sound advice... except the Apple subscription also controls features in our back-end user's profile. If the user switches accounts in our app (but remains logged in as the same iTunes user), then relying on the receipt data will end up enabling those features on the second back-end user's account. In theory, a malicious iTunes user could do this for an arbitrary number of accounts. Using the transaction id allows us to tie the original transaction to the iTunes user who actually purchased the subscription.


DTS engineer suggested we raise a radar - which I've also done (rdar://32216795). I guess I'll just have to wait and see (plus try to reproduce using the multi-device scenario)

Your server can record the user's account on your server and the app store's originalTransaction.transactionIdentifier to be sure they aren't a duplicate of some other user's account's transactionIdentifier. That is actually the standard protection against hacked receipts - make sure the transactionIdentifier for the purchase is unique.

Having the same issue in my testing environment. Were you able to find a solution ? My problem is mostly recurring purchases and with upgrading from i.e. monthly subscription to yearly. I am getting different ids for transaction_id from receipt and from transactionIdentifier from delegate. While it is probably not important I also have numeric values very close to each other like: "transaction_id" = 1000000302020911; and transactionIdentifeir = 1000000302020910;. because of this problem I can not verify that there is a successful transaction happened.

One thing to mention, I am able to reproduce this problem for 100 percent, when I purchase i.e. monthly subscription on one device and then login with the same sandbox test account on another device and do restoreCompletedTransaction. At this point I will get different transaction ids as restoreCompletedTransaction creates an id that was not in a receipt. However after that if I upgrade subscription to yearly one, I still get that transaction ids not matched.


P.S. What do you mean, when you say we have to check receipt content instead of transaction_ids ?


Cheers

Armen

Transaction id from device not in list returned from Apple
 
 
Q