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?

@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 gross 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

Which part of

>Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

am I not understanding? These are receipts from [[NSBundle mainBundle] appStoreReceiptURL]. appStoreReceiptURL is an iOS7 method. If you are running iOS6 you cannot get these receipts. If these are "iOS 6 style transaction receipts" than what receipt is not "iOS 6 style transaction receipts"?

@Rich


You said "the Verifying Receipt PG does document that these fields are present in the 'Parse the Response' section".


The documenation in the "Parse the Response" section says:


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.


I thought:

iOS 6 style transaction receipt means transaction.transactionReceipt

iOS 7 style receipts means [[NSBundle mainBundle] appStoreReceiptURL]


Is this incorrect? If so, what do "iOS 6/7 style receipts" mean?

I apologize for the delayed response - I've been swamped with DTS incidents regarding StoreKit issues.


With regards to the documentation in the Receipt Validation PG - first let me apologize for previous statements which I have made indicating that the "latest_receipt" and the "latest_receipt_info" fields are deprecated. The iTunes Store Server engineers tell me that these fields are supported. The documentation in the Receip Validation PG is current, HOWEVER, there is a misunderstanding as to the terms iOS 6 style transaction receipt. This term applies only in the case that it contains information about an auto-renewing subscription. It indicates that when the "latest_receipt" field is revalidated, it will be processed much like the deprecated transactionReceipt field is/was. If you validate a saved transactionReceipt (it still works as far as know under iOS 10.x) if the auto-renewing subscription has renewed since the transactionReceipt was saved, the validation process will include the renewal information of the auto-renewing subscription item. This isn’t the case for the in_app array of the applicationReceipt (the iOS 7 style receipt). However since the latest_receipt and latest_receipt_info fields are a part of the applicationReceipt, if there is an auto-renewing subscription item in the in_app array, there will be a latest_receipt as well as a latest_receipt_info fields which will contain the latest renewal information for the auto-renewing subscription item.


This issue needs to be clarified in the Receipt Validation PG


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Rich,


You have just confirmed that:

>This (the validation process will include the renewal information of the auto-renewing subscription item) isn’t the case for the in_app array of the applicationReceipt (the iOS 7 style receipt)

But then you went on to write:

>However since the latest_receipt and latest_receipt_info fields are a part of the applicationReceipt,

1) Where is that written in the documents?

2) If it is not in the written documents, can we rely on that?

3) Note that the "latest_receipt" and the "latest_receipt_info" will have no newer information than is in that concurrent applicationReceipt. The question is - can the content of the "latest_receipt" field in an ApplicatinReceipt be sent to the Apple servers to be updated?

PBK,


You asked

>However since the latest_receipt and latest_receipt_info fields are a part of the applicationReceipt,

1) Where is that written in the documents?

Response - In the section "Parse the Response"

The response’s payload is a JSON object that contains the following keys and values:

And of course the description is misleading.

You then asked - can the content of the "latest_receipt" field in an ApplicatinReceipt be sent to the Apple servers to be updated?

Response - yes


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Rich,


Thanks for your help here.


Please correctly if I am wrong - what you are writing is that this wording is "misleading":

"latest_receipt Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions."

It should state:

"latest_receipt Only rReturned for as an iOS 6 style transaction receipts butonly for auto-renewable subscriptions."

OMG, this thread is hurting my brain. 😟


PBK, clearly the wording of the footnotes for latest_receipt and latest_receipt_info is missleading. It seems they are solely responsible for the major confusion about these fields on every post on the internet for this subject.


However, they are still being reported for iOS 7+ (applicationReceipt) style receipts with regards to auto-renewable subscription purchases. They are in the sandbox and they are in the real world (our app uses auto-renewable subscriptions and we receive these fields from the Apple verification server).


As you have said many times, these two footnotes make it sound like they should not be there. Rich seems to indicate otherwise however as does the contents of the actual receipts.


I _think_ the wording should really say "Only returned for iOS 6 style transaction receipts with for auto-renewable subscriptions." However, like you have reiterated many times, I'm still worried they may not exist at some point.


Case in point, we receintly received a receit from a user that when sent to the Apple verification server did not come back with a 'lastest_receipt_info' field in it. This caused our code to crash since we were expecting it and unfortunately the receipt data was lost so I can't replay it.


My question then for Rich is, did this receipt not contain a 'latest_receipt_info' field because the receipt didn't actually contain an auto-renwable subscription and was potentially the user trying to decieve us or was this some case where the Apple servers randomly didn't return this field? We are very worried now about losing subscription data due to this issue.

Lusta,


You asked - did this receipt not contain a 'latest_receipt_info' field because the receipt didn't actually contain an auto-renwable subscription.

Response - if there is no auto-renewing subscription item in the applicationReceipt, in the in_app array, then when the applicationReceipt is validated, there won't be either a latest_receipt field nor a latest_receipt_info field.


You asked - was potentially the user trying to decieve us or was this some case where the Apple servers randomly didn't return this field?

Response - if the verifyReceipt server processed the receipt, the contents of the receipt have been verified by the iTunes Store. There is now the question as to the JSON contents of the receipt. My statement above stands. If there is an auto-renewing subscription item in the in_app array, but there is neither a latest_receipt field nor a latest_receipt_info field, this would be a bug report. I would save the base64 encoded applicationReceipt to include with the bug report.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Rich,


Hi, thanks for the quick reply. I appreciate it.


For your first reponse regarding: "did this receipt not contain a 'latest_receipt_info' field because the receipt didn't actually contain an auto-renwable subscription":

Unfortunately we do not have access to the receipt sent to us by the client (applicationReceipt) nor the contents of the in_app array from the validated response. When our server didn't find the 'latest_receipt_info' field it caused an error and none of the original receipt information was saved (we have since fixed that). We also were not checking for the in_app area since we assumed latest_receipt_info was sufficient. So unfortunately I can't answer your question. Am I correct though that for the case of auto-renewable subscriptions we should be using 'latest_receipt_info' and not 'in_app' to get the most current renewal / expiration information? Or will those two contain the same data?


For your second response regarding: "was potentially the user trying to decieve us or was this some case where the Apple servers randomly didn't return this field?"

I can say that no status error was returned from the Apple receipt validation as that part of code did pass so this was a valid receipt. But unfortunately it crashed right after that while trying to access the 'latest_receipt_info' field so I don't even know if the bundle id matched. What it sounds like from what you are saying though is that if an auto-renewalable subscription was in the receipt then there there should have been a 'latest_receipt_info' and 'latest_receipt' field. This seems to also answer PBK's original question, that these fields are indeed not depricated.


That would mean that one of three things happend:

  1. Fake receipt
  2. Bug on Apple's side
  3. The receipt we sent from the client hadn't yet had the purchase information added to it.


For #3 we grab the applicationReceipt after we receive a .Purchased tranasction from the SKPaymentQueue so I don't see why the receipt wouldn't include the purchase.


I'm leaning towards #1 as our backend is reporting the same number of subscriptions as Apple Analytics and if we dropped the ball I would assume Apple would report 1 more. Is there someone we can contact though to see what receipt we sent to the verification servers at this timestamp or see if a purcahse was made at this timestamp? I could used that to check the 'in_app' array. Or is there a way to download a list of all of our current active subscriptions? That would be helpful regardless.


Thanks,

Iusta

Rich wrote:

>My statement above stands. If there is an auto-renewing subscription item in the in_app array (added by PBK for clarity - in an iOS7 style receipt, not a transaction.transactionReceipt), but there is neither a latest_receipt field nor a latest_receipt_info field, this would be a bug report.


This is absolutely consistent and equally untrue. It is not a bug - it is expected behavior based on the documentation. If the field is present then that is an undocumented feature. Or shall I say, undocumented with the exception of Rich's posts on this forum - which, with all due respect, is not the same as "documented". The random absence of an undocumented feature is not a bug.


Why, oh why, doesn't Apple update its documents if this feature is reliable????? That is the bug here.


I am sorry that this thread is so long and hurts your head - but that's reality. Your 3 choices leaves out the possibility that Apple Engineers may sometimes not agree with Rich's assertion that an iOS7 Style receipt must contain these fields.

latest_receipt and latest_receipt_info fields - deprecated or not?
 
 
Q