latest_receipt and latest_receipt_info fields - deprecated or not?

You used to be able to check the current status of an autorenewable subscription by sending any old coded receipt from the app to the Apple servers and they would respond with the decoded receipt and two new fields - latest_receipt and latest_receipt_info. But the documents


https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1


say this is returned "only for iOS6 style transaction receipts" which are deprecated. Rumor (i.e. your recent post) suggests that the fields will be returned for post iOS6 style receipts (i.e. the receipt in [[NSBundle mainBundle] appStoreReceiptURL]). If so, GREAT!!!!! But is this true? Can we rely on it? When will it be documented?

Solved Answer

45 Replies

@rich -


Could you please follow up on this as you mentioned you would (https://forums.developer.apple.com/thread/65275)


Our tests today show that the receipt fields are still there in iOS 6+ receipts, but they don't contain any info about the auto-renewed subscriptions. For example: On sandbox, we buy a 1-month auto-renewable subscription. We save the full receipt and 6 minutes later send it to Apple to verify again. Nothing changes in the receipt's in_app, latest_receipt or latest_receipt_info fields to let us know that the subscription was auto-renewed at the 5-minute mark. If we open the app and get the refreshed receipt there is a new entry in the in_app, latest_receipt and latest_receipt_info fields showing that the user was billed again.


Is it possible for a user to NOT open the app after being billed and for external servers to learn about the subscription renewal?


Thanks!

With regards to the interface file SKPaymentTransaction.h and the declaration in the interface that the transactionReceipt field is deprecated, the interface file is the official declaration as to the state of this field. It's my understanding that the transactionReceipt field is still active per the iTunes Store Server engineering group, but until the interface file is changed, the transactionReceipt field is deprecated. I’m told by the iTunes Store Server engineering group that the store continues to return the transactionReceipt for a successful transaction.

While the transactionReceipt field is marked as deprecated, that doesn't mean that the latest_receipt and the latest_receipt_info JSON fields in a validated applicationReceipt (as referenced by [NSBundle mainBundle] appStoreReceiptURL]) are also deprecated. The iTunes Store Server engineers indicate that these fields are valid portions of the validated applicationReceipt.

The value of the latest_receipt_info - once this information is captured for an auto-renewing subscription in-app purchase item, the latest_receipt_info can be used independently to view the renewal status of the auto-renewing subscription item (and items in the group). I refer you to the statement in the “Receipt Validation Programming Guide” <https:/

“The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt.”

The above statement is from the iTunes Store Server engineering team and explains that once the latest_receipt_info field has been captured, that field is base64 encoded and can be resent to the appropriate verifyReceipt server. The JSON response can be parsed and will provide the latest information about the auto-renewing subscription item. The result can contain multiple items, and for this reason. As such the status result 21006 does not apply. This is because there can be multiple items in the response and the expired status may not apply to all items. When the status of 0 is returned, the receipt was successfully validated and the app (or server process) must process the returned results individually.

In my testing, with a subscription group, I found that by capturing the latest_receipt_field from the initial purchase, I could then validate the latest_info_results contents and watch as the auto-renewing subscription item renewed. If I switch to another auto-renewing subscription item in the group, then validated the same original receipt, the change to the different auto-renewing subscription group item was recorded. You can perform this test yourself in the sandbox to see the results.

I kept the contents of the first applicationReceipt from which I used to capture the initial latest_receipt_info contents. In this initial JSON result, there was the single item in the in_app array. Later I validated the same applicationRecept after the renewal occurred (in the sandbox) and found that the in_app array still had the one auto-renewing subscription item, but the latest_receipt now contained a second item with the auto-renewing subscription renewal. As the subscription renewed, I validated the exact same applicationReceipt - with similar results, the in_app array maintained the one item, but the latest_results fields showed the renewals.

One additional note, a user has the option to terminate an auto-renewing subscription item in their iTunes account. The server process can only detect an expired auto-renewing subscription when there is no active auto-renewing subscription item in the JSON results (in_app array or in the latest_receipt_info). In addition, the user can restart an expired subscription in their iTunes account. By validating the latest_receipt, a server process can detect that the expired auto-renewing subscription item has been restarted.

This mechanism makes it possible for a server process to track the auto-renewing subscription renewal process rather than do so on the app. The one thing that the server renewal process cannot track is a cancellation. By cancellation, I mean when the user with an active auto-renewing subscription contacts Apple Care to complain that there was some problem and requests a refund. If the refund is approved, the subscription is cancelled. The iTunes Store Server engineers have proposed a means to handle this in the latest_receipt, and I’ve asked the team to document the process. I expect that the Receipt Validation Program Guide will be updated when such change is finalized. In the meantime, the only official means that I’m aware of to detect a cancelled auto-renewing subscription is to have the application refresh the applicationReceipt, then validate the applicationReceipt. In such case, there will be a “recent” auto-renewing subscription item where the cancellation_date field is set with the date of cancellation.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

I should also add, I use the following curl command to manually process the base64 encoded receipt contents. Using the curl command is similar to a server performing the validation process.


curl -d '{ "password":"pppp" "receipt-data": "xxxx"}' https://sandbox.itunes.apple.com/verifyReceipt


where pppp is your shared secret, and xxxx is the base64 encoded receipt.


Make sure to change the verifyReceipt server URL if you are validating a production receipt.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Thanks for your substantive reply.


You wrote: >.......the latest_receipt and the latest_receipt_info JSON fields in a validated applicationReceipt (as referenced by [NSBundle mainBundle] appStoreReceiptURL]) ......The iTunes Store Server engineers indicate that these fields are valid portions of the validated applicationReceipt.


This would be WONDERFUL if we could rely on it. Unfortunately it is inconsistent with:

https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

latest_receipt Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The base-64 encoded transaction receipt for the most recent renewal.

latest_receipt_info Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The JSON representation of the receipt for the most recent renewal.


Is this a feature that will disappear or is it a feature that will be documented?




You wrote >The one thing that the server renewal process cannot track is a cancellation. By cancellation, I mean when the user with an active auto-renewing subscription contacts Apple Care to complain that there was some problem and requests a refund. If the refund is approved, the subscription is cancelled.


Why wouldn't the latest_receipt_info contain a cancellation_date field (in the one receipt for that transaction) immediately after the cancellation?


Rich,


Thank you for the response!


We did the same test as you but I think we did it on a sandbox account that had already had a receipt renew 5 times that day. So we didn't get any renewals and that confused us. Making a brand new test account worked - we see the renewed receipts added to the latest_receipt field 🙂 Thanks!


PBK - I believe in other posts you have mentioned that the fields latest_receipt and latest_receipt_info are unreliable and don't always show up in iOS 7 receipts. We have yet to see this happen but we only recently started researching auto-renewable subscriptions. This is very concerning if the engineers told Rich they are valid portions of the receipt yet developers don't always see the fields.


[Edited to remove unclear references to Rich's post above]

>...you have mentioned that the fields latest_receipt and latest_receipt_info are unreliable

> ......the engineers told Rich they would always be there....


The latest_receipt and latest_receipt_info fields are not actually documented to exist in iOS7 and later receipts dispite Rich's possible suggestions otherwise. On various occasions users have reported that the fields are absent and then they return. There was a campaign a while ago to ask that this 'feature' be made permanent in iOS7 receipts and later but there has been no response from Apple. Please add your name to those requesting this enhanced feature.


Rich is not reporting that the engineers told him "they would always be there" - just that they are currently "valid portions" of the receipt. They could disappear tomorrow.


Think about it. Decoding a receipt is easy - you do not need to access a backend, very current database. Adding those fields requires searching the database for a new entry for each decode request. It may well be a feature that Apple wants to stop. And to add insult to injury, there are those developers who take ALL their receipts and run them EVERYDAY to determine which users are maintaining an active subscription. Do the numbers - for 30% of maybe $1.99 (Apple's ***** on a 3 month autorenewable subscription) Apple has to run the database search at least 90 times. This could be a real headache for Apple.

Thanks PBK and apologies for the poor wording.


I agree it could be a headache for Apple to scan their db every time /verifyReceipt is hit, so I could see them removing that functionality. I think we're both on the same page: we want to know if Apple has plans to make it an actual documented feature we can rely on.


For our use case, and I imagine many others, it's not very useful to have a subscription system that doesn't allow an external server to validate a user's subscription without the user opening the app. Unless we know Apple currently supports and plans to continue supporting a method by which we can externally verify subscriptions, I think we'll be going with a non-renewable subscription approach.

Ask yourself why you can't just let the app itself determine when to check for a renewal notice. The app detects date based expiration and opens an observer for a new transaction (which should be automatically delivered if the subscription is current and the device has executed a restoreCompletedTransaction or a purchase). If it doesn't come (fail safe here) the app tells the user they need to renew. Whenever the app gets a renewal or purchase transaction it tells your server. It could hand over the then current receipt to your server if you want to protect against 99% of the hacks. The few users who buy and then cancel a subscription might be easily suffered. No one can do that more than once or twice without Apple saying 'no'.


All that said - non-renewal subscriptions give you much more flexibility.

We're not as concerned about hacking or cancelling - we have those situations figured out.


Our game runs on multiple platforms and subscriptions can be bought on all of them (e.g. Netflix, Pandora, LinkedIn, etc). Imagine a user who purchases a 1-month recurring subscription on iOS and then stops using the app on their iPad and only uses it on the computer. They get an email from Apple saying "You have been charged and your subscription has been renewed" after which they log in to our website. If we don't have a reliable way of knowing if their subscription has been renewed, we have to direct them to open the app on their device. That's not acceptable in our opinion.


We have confirmed with our Apple representative that our approach conforms with the review guidelines. However, if the ability to validate subscriptions externally without requiring the user to open the app isn't a feature Apple plans to officially support now and in the future, I don't see us or many others using auto-renewable subscriptions.

I am unfamiliar with your use case in which a subscription is shared between an iOS device and a Mac.


Be sure to submit an enhancement request using the bug reporter system.


"I don't see us or many others using auto-renewable subscriptions" is an interesting way of negotiating a feature that you want. However it fails on its face - many others are using auto-renewable subscriptions. Maybe an "...even more apps would use auto-renewable subscriptions if...." might work better.

PBK,

You stated - This would be WONDERFUL if we could rely on it. Unfortunately it is inconsistent with:

latest_receipt Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The base-64 encoded transaction receipt for the most recent renewal.

latest_receipt_info Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The JSON representation of the receipt for the most recent renewal.

You are correct to point to this inconsistency. The issue lies with the declaration that they are “iOS 6 style transaction receipts” - this is what is returned with a successful purchase transaction to the updatedTransactions delegate method - regardless of purchase type. For an auto-renewing subscription, when validating the transactionReceipt, there was the benefit that the current renewal information was returned. The validated receipt returned information for one auto-renewing subscription transaction with updated renewal information. It was also the case that a status result of 21006 could be returned to indicate that the auto-renewing subscription item was expired.

When you validate the latest_receipt with auto-renewing subscription information, you will see that there can be multiple records. This indicates that the description of the latest_receipt and the latest_receipt_info fields are out of date. My view of these fields is that once they returned the most recent information, but now they return a history of the auto-renewing subscription renewals. I’ve submitted a bug report that these two fields be clarified.

What appears to have remained constant are the receipt field names. My advice is to view the contents of latest_receipt and to search for active auto-renewing subscription items. If there is no item which has an expires_date field later than the current date, the auto-renewing subscription is expired. While the historical auto-renewing subscription items are present, if you need them, save them to your own records so you don’t become dependent on their presence in the latest_receipt (or in the in_app array of the JSON results of the applicationReceipt as well)

You also asked - “why wouldn't the latest_receipt_info contain a cancellation_date field (in the one receipt for that transaction) immediately after the cancellation?

Response - Good question, but it’s not there, and no explanation or documentation has been provided.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

The applicationReceipt which is stored in a application is generated by the iTunes Store Server. It’s format will be the same regardless of iOS version. There are differences between the applicationReceipt for an iOS app to a macOS in-app purchase application. If users report that the latest_receipt and the latest_receipt_info fields are missing - for an applicationReceipt with an auto-renewing subscription item, this would be a bug report. It would help to include the base64 applicationReceipt as a test file enclosure with the bug report so that the matter can be investigated.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Huh?


>this is what is returned with a successful purchase transaction to the updatedTransactions delegate method - regardless of purchase type.

You are referring to transaction.transactionReceipt - that's what is 'returned...to the updatedTransactions method'. My point is that that's deprecated:

https://developer.apple.com/reference/storekit/skpaymenttransaction/1617722-transactionreceipt?language=objc

It would not be a bug report. It would be a feature request. Those fields are only in iOS6 Style receipts. Let me restate the current situation:


1) transaction.transactionReceipt is DEPRECATED. It may disappear. But if you get one and decode it yourself it will NOT contain a latest_receipt or latest_receipt_info field - how could it! However, if you send it to the Apple servers they WILL ADD those two fields with valid current information - even if the receipt is not the latest receipt.

2) if you get your receipt from [[NSBundle mainBundle] appStoreReceiptURL] , as you should, and decode it yourself it will not contain the latest_receipt or latest_receipt_info fields - how could it! If you send it to the Apple servers they MAY OR MAY NOT ADD those two fields with valid current information. Today they are being added. Who knows about tomorrow - DO YOU???? This is a wonderful UNDOCUMENTED feature, we want Apple to keep it.

PBK,


I understand your thoughts. With regards to verifying a transaction.transactionReceipt, I haven't done this is a long time. You are correct, if you get one, it will not contain a latest_receipt or latest_receipt_info. I was unaware that if you validated the transactionReceipt with the Apple verifyReceipt server, that they would be added. I'll have to check this out.


As for the second part - if you decode the applicationReceipt, we don't document that it will contain the "latest_receipt" or "latest_receipt_info" fields. However, the Verifying Receipt PG does document that these fields are present in the "Parse the Response" section. As to the contents of the latest_receipt and the latest_receipt_info fields, I agree that they could be better documented. It's for this reason, I stuck my head out to document my latest findings. I'm certainly with you, that there are some areas where we could improve documentation.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI