What is the purpose of latest_receipt in IAP?

There is one thing I don't quite understand when it comes to In-App Subscription purchase.

I obtain the receipt on iOS client like this:


private func loadReceipt() -> Data? {
        guard let url = Bundle.main.appStoreReceiptURL else {
            return nil
        }

        do {
            let receipt = try Data(contentsOf: url)
            return receipt
        } catch {
            print("Error loading receipt data: \(error.localizedDescription)")
            return nil
        }
    }


And send it for verification to my server (written in Python).


def verify_receipt(self, receipt):
     r = requests.post(config.APPLE_STORE_URL, json=receipt)
     request_date_ms = DateUtils.generate_ms_from_current_time()
     for item in r.json()['latest_receipt_info']:
          expires_date_ms = int(item['expires_date_ms'])
          if expires_date_ms > request_date_ms:
               return True
     return False


I get the

expires_date_ms
from
latest_receipt_info
, and if it's greater than the current time in milliseconds, then the subscription counts as still valid.


1) Would you say this is a solid way of verifying if the subscription is valid?


2) What is the exact purpose of

latest_receipt
here? Is it a copy of the receipt that I just passed in? Could it be newer due to the latest attempt at subscribing? Should I save this one to the database for the current user, and test this receipt from now on going forward to see if the user is still subscribed?


Thank you very much for your advice,

Replies

> 1) Would you say this is a solid way of verifying if the subscription is valid?


It is a valid way of detecting the subscription is valid. It is also a valid way of detecting the contra negative - that a subscription has expired. If you examined just the 'receipt' part of the receipt (e.g. decode it yourself in the device) then you might be dealing with an old receipt that does not reflect a recent renewal of the subscription and only indictes that the old subscription has expired. But because you are sending it to Apple and getting the latest_receipt_info your subscription status will be current. (If you decode the receipt yourself and it indicates 'expired' then you need to refresh the receipt to be usre you are dealing with the latest receipt.)


> 2) What is the exact purpose of

latest_receipt
here?


See answer to #1


> 3) Is it a copy of the receipt that I just passed in?


No. It is the latest_receipt.


> 4) Could it be newer due to the latest attempt at subscribing?


Yes


> 5) Should I save this one to the database for the current user, and test this receipt from now on going forward to see if the user is still subscribed?


It doesn't matter.

Thank you for your detailed reply. It was incredibly helpful.


On the server side, I also need to periodically check if the subscription is still valid and deny otherwise access to the premium content.


In order to achieve that,

1) I was planning to save the initial receipt that I got from Bundle.main.appStoreReceiptURL on the server.

2) Then, for each user, send the stored receipt periodically to https://buy.itunes.apple.com/verifyReceipt and check if the subscription within latest_receipt_info is still valid, otherwise, delete user's premium access.


Is it enough to do these checks with the initially stored receipt? Or do I have to replace that stored receipt with the latest_receipt everytime I make a call, and do these checks only with the latest_receipt after all?


I have a feeling the initial receipt is enough, as all I care about is latest_receipt_info anyway, but I'm not sure.


I hope this makes sense,

Many Thanks

>Is it enough to do these checks with the initially stored receipt?


Yes.


>I also need to periodically check if the subscription is still valid


Because 'cancellations' are so rare, it really is only necessary to check the subscription when the last renewal record in your file suggests it might have expired.