Unusual results doing Server verification of IAP receipts

I have a system where the app has sent its original transaction receipt (iOS6 style) to the server, and the server diligently verifies it whenever the latest receipt expiry time comes around. This is done entirely on the server after the initial purchase with no further input from the App, because Apple returns the latest receipt each time I do the verify request.


This has worked great so far. However, with increased volume recently I have had some false negatives. On a subscription that has not been cancelled, when I send my verification request Apple is sometimes returning the 21006 error code and giving me a typical expired response as though there hasn't been a new receipt created yet. My server always checks on the hour after the expiry time. Is this too short a time period after the expiry? Do I have to allow more time for Apple to renew the receipt information?


When I look at an example bad response, It has status 21006, it has a latest_expired_receipt_info field where the receipt is the same info as the latest one I received last month. It is as though the new receipt just isn't there yet even though I know this subscription is not cancelled.

For these cases, when I notice them and know for a fact the subscription was not cancelled, I re-trigger the server verification manually, and on this manual attempt (usually hours after the first expiry-time-is-up check) I do get a fully valid new receipt back.


Does anybody have any ideas what could be causing this behaviour? It is very confusing to me but seems wrong that Apple would ever return the wrong data.



I have considered upgrading to the newer app receipt method instead, Can the new App receipt system be used in a similar manner without further input from the App? I would not be able to replace all of the iOS6 style receipts already on my server anyway though, so I would have to keep using both systems.

Answered by in 156580022

I hate to be the bearer of bad news on this subject, The latest_receipt field in the applicationReceipt is still the iOS 6 style of receipt which as per the SKPaymentTransaction.h interface file, the transactionReceipt is deprecated as of iOS 7. iTunesConnect continues to return the transactionReceipt and the latest_receipt_info section of the applicationReceipt.


If there is a desire for offline support of auto-renewing subscriptions, this is an enhancement request for iTunesConnect to implement. Please submit the ER using the Apple Developer Bug Report web page <http://bugreport.apple.com>


Please understand that as a DTS engineer, I support the use of the iOS API's which are implemented by iOS engineering. The issue here is not with the use of the API's, but with the processing of the receipt as managed by iTunes Connect. As such, where there are anomalies, I can assist with the submission of bug reports for iTunes Production Support to investigate. My recommendation, as presented in my response to the developer forum article <https://forums.developer.apple.com/thread/48386> is to base the status of an auto-renewing subscription on the contents of the in_app array of the applicationReceipt.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

>Does anybody have any ideas what could be causing this behaviour?


The iOS6 transaction.transactionReceipt has been deprecated for many years and may now be failing since it is no longer fully supported. I believe there are posts in the forum reporting this problem starting about one month ago.


You cannot use the same technique using the post-iOS6 receipt - those receipts do not generate the 'latest_receipt_info' field when decoded by the Apple servers (i.e. they are just decoded, not enhanced). You need to get a new receipt from the device each renewal period.

That seems like a serious backwards step? I was assuming I could use the app receipt in a similar way, because in my testing with the new app receipts, when I send the app receipt for verification to Apple, the response does seem to contain the full list of transactions, including transactions newer than the most recent at the time I gathered the app receipt (on the apple sandbox system at least). Can I not use the list of transactions within the response here to implement a similar system to what I described above (the server can check that it has a record of every transaction listed in the receipt)? Or was I mistaken about the verification response and it will never contain newer transactions than what the app knew about at the time it sent the app receipt?


That is sad to hear regarding the iOS6 system.

You can no longer rely on the Apple servers to update your receipt. You were not mistaken in that the iOS6 receipts (transaction.transactionReceipt) did cause the Apple servers to update the receipt as you have seen. But sadly, that era is ending.

I have performed some testing on the apple sandbox and found that a 'latest_receipt' field and a 'latest_receipt_info' field are being returned when I try to verify the post-iOS6 receipt from my server. In other words this DOES seem to give me the most recent information that I need, such that I don't need to fetch a newer version of the receipt from the phone every month and can instead keep sending the old one.


I will continue to do some testing but this seems to contradict what you were saying. Can you confirm this behaviour perhaps?

Let me ask you -


are you saying that you sent a receipt obtained from:

    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptURL];

to the Apple servers and they responded with a field called latest_receipt and latest_receipt_info that contained valid content


OR


are you saying you sent a receipt obtained from a device running iOS7 or beyond obtained from:

transaction.transactionReceipt;

to the Apple servers and they responded with a field called latest_receipt and latest_receipt_info that contained valid content


If the later; that is well known, deprecated and reported to be failing in the Production environment on a regular basis.


I am saying you won't get a valid latest_receipt_info in the former.


I would love to hear that I am wrong - from you or anyone else. Although I wouldn't rely on the system not changing pretty soon.

I was indeed talking about the former, it is NOT a transactionReceipt but the app-level receipt. However I would appreciate if anybody else can also confirm this behaviour as I am also not trusting this right now.

I can confirm from hundreds of logs that renewable subscriptions implies that a latestReceipt field is present in Application receipt json returned by Apple server (if a renewal occured).


Edit: as an aswer to PBK, I am reporting about ApplicationReceipt, not transactionReceipt.

Once again, is this transaction.transactionReceipt or [[NSBundle mainBundle] appStoreReceiptURL];

[[NSBundle mainBundle] appStoreReceiptURL]

Accepted Answer

I hate to be the bearer of bad news on this subject, The latest_receipt field in the applicationReceipt is still the iOS 6 style of receipt which as per the SKPaymentTransaction.h interface file, the transactionReceipt is deprecated as of iOS 7. iTunesConnect continues to return the transactionReceipt and the latest_receipt_info section of the applicationReceipt.


If there is a desire for offline support of auto-renewing subscriptions, this is an enhancement request for iTunesConnect to implement. Please submit the ER using the Apple Developer Bug Report web page <http://bugreport.apple.com>


Please understand that as a DTS engineer, I support the use of the iOS API's which are implemented by iOS engineering. The issue here is not with the use of the API's, but with the processing of the receipt as managed by iTunes Connect. As such, where there are anomalies, I can assist with the submission of bug reports for iTunes Production Support to investigate. My recommendation, as presented in my response to the developer forum article <https://forums.developer.apple.com/thread/48386> is to base the status of an auto-renewing subscription on the contents of the in_app array of the applicationReceipt.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

I think I understand what is happening here.


Clearly the receipt, as presented to the Apple servers, has no 'latest_receipt_info' field in it - how could it! But the Apple servers dig up that information and append it to their response. This action is documented for iOS6 style receipts - the transaction.transactionReceipt. But they are deprecated and will disappear 'soon'. I bet Apple is not doing that now because some app of 'importance' is still using transaction.transactionReceipt. But at some point they will stop providing and decoding those receipts. While they support the iOS6 receipts they are providing the same 'look back and append latest_receipt_info' for the newer receipts - even though that is not documented. Because it is not documented, I suspect they are planning to stop providing that service at the same time that they stop supporting the now-deprecated transaction.transactionReceipt; otherwise they would document the latest_receipt_info for the new receipts.


So the race is on - will enough developers submit an enhancement request before the service disappears or will they wait to complain when it happens? The service is useful if you don't want to require that the user be logged into their iTunes Account each renewal period. But then again, maybe you do want to require that user has access to the correct iTunes Account each period to prevent 'friends use' of a subscription.

First, to calrify: We are not using the latest_receipt_info json field programatically, since it is undocumented and also because we want the device to be identified to the right account to receive the renewing transaction. But this latest_ stuff has proven useful on many occasion when manually inspecting our users situation where they have a renewal pending and not valiated on their device, most of the time because of a mistake on Apple ID.


PBK guess might be right. Nevertheless, there is something I do not understand in Rich reply : "The latest_receipt field in the applicationReceipt is still the iOS 6 style of receipt which as per the SKPaymentTransaction.h interface file"

  • I did not check the b64 encoded latest_receipt field from some time now so I'll not comment on its format.
  • But the latest_receipt_info field (json stuff returned by Apple server) is NOT old-style. It has the exact same format, fields and fields content as the main in_app field, listing IAPs. Not those found in transactionReceipt.

Maybe there is some confusion between these two field in Rich's answer ? Notice that the former (b64) is a subfield of the second clear text json.


There is still some confusion on the subject and my own guess is that "big companies" have already firmly asked for such a feature and it is there, in "new" format. Will it stay, I can't certainly tell. But, as long a it does this is a useful piece of info.

It may be that the receipt info is not the same format as a transactionReceipt. The focus of my response was not for the content of the receipt, instead that one should not rely on the validation support provided to this receipt to be similar to that of the iOS 6 transactionReceipt. There is a desire to find support for offline receipt validation - which is presently not documented as supported by validating the applicationReceipt. Such support should be submitted as an enhancement request using the Apple Developer Bug Report web page - http://bugreport.apple.com. Make sure to select the iTunes Connect product in submitting this enhancemnet request.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Unusual results doing Server verification of IAP receipts
 
 
Q