Anyone experiencing issues with user subscriptions not working during last 24 hours?

Users open the apps, shows they must subscribe even though they’re already within a paid subscription period. They tap subscribe and it says they’ve subscribed. Tap restore and it says they’re subscription isn’t currently active. Apple isn’t returning proper subscription data. I see on another forum someone else has asked the same question but has anyone reached Apple about this and gotten a response? It’s been over 24hrs and this can be detrimental to business.

  • Recurring issue with magazine subscriptions, e.g., The Atlantic, GQ, etc.. Despite deletions, downloading, issue still remains. Distressing.

Add a Comment

Accepted Reply

I reviewed your receipt validation code - the issue is that the for loop is such that the assumption occurs that the last item in the latest_receipt_info array is the most current item. The issue for some of the developer postings here is the following


It appears that some app receipt validation code makes the assumption that when analyzing the contents of the latest_receipt_info section, that the last item in the latest_receipt_info section is for the current active subscription. When the expiration date for this item is earlier than the current date, the app process thinks that the subscription is now inactive.


This is an incorrect assumption. This is an issue that isn’t easily checked in the sandbox as it is more likely to occur when there are multiple subscription transaction records for the user. When searching the latest_receipt_info section for an active subscription, the app should check each item in the latest_receipt_info - if there are multiple item in the array. The array item showing the subscription is still active could be the first or second item in the latest_receipt_info array. However, the most current element of the array is not guaranteed to the the most recent.


DTS advises that if the app process is only interested in active subscription info, the app process should pass in the


"exclude-old-transactions": true key

In the JSON payload sent to the verifyReceipt server.


When the validated response is received, the app process need only look at each item in the latest_receipt_info section to know which items are active. For a user with only one active subscription, there will only be one item in the latest_receipt_info.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Replies

Yes, similar issues here!
I try to validate, that the user is subscribed to my in-app subscription, upon app launch. Since more than 24 hours (perhaps close to 48) this causes the app to freeze/crash. Seems to happen mostly for users that are actually subscribed. Another issue is that for some users an active subscription is not detected (no crash).
There cleary seems something wrong with the https://buy.itunes.apple.com/verifyReceipt server.
I reached out to Apple Developer Support. They couldn't help me and told me that it is best to contact technical support, which I haven't so far.
This is a very annoying bug concerning revenue and subscription numbers... Please Apple fix it.

One of my users is now getting this message for a recently renewed auto-renewable subscription:


PurchaseOperation: [A3AD40F5] Purchase finished with error: Error Domain=SSErrorDomain Code=16 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store}


Something appears to have broken with auto-renewable subscriptions. When tapping to purchase a subscription the correct information appears showing the user is subscribed with the correct expiration date. However, the actual renewal is not confirmed and the user cannot progress past the purchase screen. This behavior does not appear in the sandbox... only in production. Restore purchases doesn't work as well.


It would make sense that the verifyReceipt server is broken... but I can't think of a way to determine this with the production version of my app.

Yes our users too are facing this issue. One strange thing I noticed is that free trial subscription(production) and sandbox subscription are working fine.

Problem occurs only when we purchase production non free trial purchases.

Do you guys experience same problem?

We are really worried about it since we have received many messages and mails from our app subscribers complaining about this.

This number keeps on growing. They are asking us for refunds if we can't provide any solution.

We are seeing similar behaviour with re-purchases and restores of subscriptions. I've had a complaint from production but also seem to be able to reproduce in the TestFlight sandbox as well. From what I can tell, when you repurchase or restore, a new transaction is not being added to the queue and thus there is no receipt to send to the server for verification. At least in my case, the /verifyReceipt endpoint appears to be working OK.

We're experiencing the same issue as well. Lots of users are sending us emails and tickets about the issue. We've changed nothing (our last update was 3 months ago), then yesterday it started malfunctioning. Receipt validation fails but we cannot debug it since it only happens in production. Need help ASAP!!!

Hi,


I have the same problem. One of my apps (after updating to iOS 13.5) not see subscriptions (subscription older than a year). Subscription in other app works fine (subscribed from a month). Sandbox seems to work fine, at least see some receipts ...

Just wanted to give an update that this appears to have been a problem with my subscription checking code.


I previously had logic like this:


  1. Get a list of all IAP receipts from Apple
  2. Pick the last one from the list and assume it is the latest
  3. Check the expiry date and lock/unlock subscription based on that


I guess Apple used to return these in order so picking the last one was OK. Now they are returning in a different order. Changed the logic to be like this:


  1. Get a list of all IAP receipts from Apple
  2. Sort the receipts by expiry date ascending
  3. Pick the last one from the list
  4. Check the expiry date and lock/unlock subscription based on that


After pushing out this change, I had confirmation from two of my complaining customers that they were able to unlock their subscription. Not sure if this is the same thing that other people in the thread are experiencing but thought I would mention it just in case!

That was it 😉


Thanks a lot

Hi,
Thanks for your input!
Unfortunately I can't get it to work and have no idea what could be the reason. My app is still crashing when trying to verify the subscription.
I use the code below (shortened without catch blocks and if/else optional unwrapping) with a function that iterates over all receipts and picks the one with the latest expiry date.
While debugging in Xcode and contacting https://sandbox.itunes.apple.com/verifyReceipt, everything works and it seems that receipts are still returned by Apple in an ordered sequence.
Every help is very much appreciated!

let receiptData = NSData(contentsOf: Bundle.main.appStoreReceiptURL!)
let receiptToString = receiptData!.base64EncodedString(options: [])
let dict = ["receipt-data" : receiptToString, "password" : "[app store connect shared secret]"]
let request = try JSONSerialization.data(withJSONObject: dict, options: []) as Data
let storeRequest = NSMutableURLRequest(url: URL(string: "https://buy.itunes.apple.com/verifyReceipt"))
storeRequest.httpMethod = "POST"
storeRequest.httpBody = request
let session = URLSession(configuration: URLSessionConfiguration.default)
let dataTask = session.dataTask(with: storeRequest as URLRequest, completionHandler:{(data: Data?,...) -> Void in
  let jsonResponse = try (JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary)!
  let expDate = self.expirationDateFromResponse(jsonResponse: jsonResponse)
  // decide on unlocking subscription based on expDate
})
dataTask.resume()

private func expirationDateFromResponse(jsonResponse: NSDictionary) -> Date? { 
    var latestDate: Date? = nil 
    if let receiptInfo: NSArray = jsonResponse["latest_receipt_info"] as? NSArray {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
        for receipt in receiptInfo {
            if let dicReceipt = receipt as? NSDictionary {
                if let expirationDate = formatter.date(from: dicReceipt["expires_date"] as! String) {
                    if latestDate == nil {
                        latestDate = expirationDate
                    } else if latestDate! < expirationDate {
                        latestDate = expirationDate
                    }
                }
            }
           
        }
    }
    return latestDate
}

Hi. I was thinking about order and I had sorted receipts too, but it didn't help me. Subscription in Production still fails. I described more in that thread: https://forums.developer.apple.com/thread/133538

I reviewed your receipt validation code - the issue is that the for loop is such that the assumption occurs that the last item in the latest_receipt_info array is the most current item. The issue for some of the developer postings here is the following


It appears that some app receipt validation code makes the assumption that when analyzing the contents of the latest_receipt_info section, that the last item in the latest_receipt_info section is for the current active subscription. When the expiration date for this item is earlier than the current date, the app process thinks that the subscription is now inactive.


This is an incorrect assumption. This is an issue that isn’t easily checked in the sandbox as it is more likely to occur when there are multiple subscription transaction records for the user. When searching the latest_receipt_info section for an active subscription, the app should check each item in the latest_receipt_info - if there are multiple item in the array. The array item showing the subscription is still active could be the first or second item in the latest_receipt_info array. However, the most current element of the array is not guaranteed to the the most recent.


DTS advises that if the app process is only interested in active subscription info, the app process should pass in the


"exclude-old-transactions": true key

In the JSON payload sent to the verifyReceipt server.


When the validated response is received, the app process need only look at each item in the latest_receipt_info section to know which items are active. For a user with only one active subscription, there will only be one item in the latest_receipt_info.


rich kubota - rkubota@apple.com

developer technical support CoreOS/Hardware/MFI

Thanks for your explanations.

The following code now seems to work for me in production in combination with “exclude-old-transactions: true":

private func expirationDateFromResponse(jsonResponse: NSDictionary) -> Date? {
       var latestDate: Date? = nil
       if let receiptInfo: NSArray = jsonResponse["latest_receipt_info"] as? NSArray {
           let formatter = DateFormatter()
           formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
           for receipt in receiptInfo {
               if let dicReceipt = receipt as? NSDictionary {
                   if let productID = dicReceipt["product_id"] as? String {
                       if productID == "[subscription_product_id]" {
                           if let expirationDate = formatter.date(from: dicReceipt["expires_date"] as! String) {
                               if latestDate == nil {
                                   latestDate = expirationDate
                               } else if latestDate! < expirationDate {
                                   latestDate = expirationDate
                               }
                           }
                       }
                   }
               }
           }
       }
       return latestDate
}