🤘 We're hiring: join our team today.Learn more
Apphud
Why Apphud?PricingBlogContactSign inStart for Free
Ren
Ren
October 19, 2019
7 min read

How To Implement Apple Receipt Validation

Complete guide on how to implement App Store receipt validation using Swift. View answers to common questions about validation that iOS developers ask.

How To Implement Apple Receipt Validation

What is App Store receipt?

It's a signed file in a PKCS#7 format, which contains information about all in-app purchases in the app. It's located in the app bundle and can be easily read by calling Bundle.main.appStoreReceiptURL.

Does a receipt always exist in the app?

If a user downloaded the app from the App Store – yes. However, in sandbox if your app was installed via Xcode or Testflight, then there won't be a receipt until you make a purchase or restore.

What does "Receipt validation" mean?

It basically means to decrypt encrypted receipt file, get JSON data and verify purchases.

Why Is Receipt Validation Important?

There are two important reasons for iOS receipt validation. First, you can ensure that your customers are getting access to what they paid for. This is particularly important when they have a subscription to your app's services. 

Secondly, Apple receipt validation from the server-side helps protect your app against piracy. Many people fraudulently try to get in-app purchases via fake receipts, but App Store receipt validation stops this in its tracks.   

How Does Receipt Validation Work?

It's possible for iOS receipt validation to be done locally; however, it's more commonly done via a server-to-server configuration. 

The typical App Store receipt validation flow consists of the following steps.

1. The customer makes an in-app purchase.

2. The app store notifies the app about the purchase.

3. The developer sends a receipt to the server for validation via SDK.

4. The server calls Apple’s “verifyReceipt” endpoint and receives a JSON response.

5. The server validates the purchase. While doing so, it either tags the purchase as fraudulent or creates a regular purchase event.

6. The response is transferred to the SDK. 

7. The Apple receipt validation response is transferred as a success or failure to the app.

When do I need to validate a receipt?

  • In case of auto-renewable subscriptions when a purchase has just been made – to get an expiration date.
  • When restoring in-app purchases. If user has reinstalled the app or launched it from a new device, you must provide a mechanism to restore his purchases and give access to features he already paid for. 
  • A couple of years ago, when jailbreak was commonly used, developers used to validate receipts to verify that payment wasn't hacked – I believe those days are gone now, and it's not so necessary anymore.

Which in-app purchases can I restore via receipt validation?

There are four types of in-app purchases: consumables, non-consumables, non-renewing subscriptions and auto-renewable subscriptions. You can restore all except consumables.

Consumable purchases are, for example, coins in your app – something that can be purchased many times. There is no way to restore the number of your coins, you should keep it on your server.

A non-consumable purchase, on the other hand, is used once but doesn't expire (like a song you purchase from a music app). This kind of purchase can be restored via in-app purchase receipt validation.

What are the validation methods?

You could choose between three validation approaches: 

  • local validation using OpenSSL,
  • online validation through Apple directly from your iOS device,
  • online validation through Apple using your server.

Which validation method is better?

Well, local validation is too complicated and it's hard to implement it. Besides that, you have to add OpenSSL library into your Xcode project. And in some cases you will need to refresh the receipt.

Apple doesn't recommend Online validation because of security reasons: HTTPS request can be intercepted via man-in-the-middle attack.

It's better to validate receipts using your own server. Especially, Apple adds new fields to the receipt, like grace_period_expires_date or subscription_group_identifier. You can apply changes on your server without app update. Besides that, user can easily hack those two methods just by changing system date on device.

What is Shared Secret?

It's a special string key, which a developer uses to validate receipts with auto-renewable subscriptions. You will put Shared Secret into HTTPS request parameters.

Where can I get Shared Secret?

Go to App Store Connect, open your app, then go to "Functions" and in "In-App Purchases" tab you will see "App-Specific Shared Secret" button. Generate a new key, if it doesn't exist.

How to Validate an In-App Purchase Receipt in Swift: Example code

func validateReceipt(){

        #if DEBUG

                   let urlString = "https://sandbox.itunes.apple.com/verifyReceipt"

               #else 

                   let urlString = "https://buy.itunes.apple.com/verifyReceipt"

               #endif

        guard let receiptURL = Bundle.main.appStoreReceiptURL, let receiptString = try? Data(contentsOf: receiptURL).base64EncodedString() , let url = URL(string: urlString) else {

                return

        }

        let requestData : [String : Any] = ["receipt-data" : receiptString, 

                                            "password" : "YOUR_SHARED_SECRET", 

                                            "exclude-old-transactions" : false]

        let httpBody = try? JSONSerialization.data(withJSONObject: requestData, options: [])

        var request = URLRequest(url: url)

        request.httpMethod = "POST"

        request.setValue("Application/json", forHTTPHeaderField: "Content-Type")

        request.httpBody = httpBody

        URLSession.shared.dataTask(with: request)  { (data, response, error) in

            // convert data to Dictionary and view purchases

        }.resume()        

    }

This is a Swift receipt validation example from an iOS device. Don't forget to change YOUR_SHARED_SECRET with your own shared secret.

After you get data, convert it into Dictionary:

DispatchQueue.main.async {

	if let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: .allowFragments){

    // your non-consumable and non-renewing subscription receipts are in `in_app` array

    // your auto-renewable subscription receipts are in `latest_receipt_info` array

  }                

}

Example of decrypted JSON App Store receipt

Here you can view an example of JSON receipt with two transactions for auto-renewable subscription.

What's the difference between <code class='inline-code'>in_app and latest_receipt_info</code> ?

  • latest_receipt_info contains all transactions including subscription renewals.
  • in_app contains transactions for non-consumables and non-renewing subscriptions. There will also appear only the first receipt for your auto-renewable subscription. Consumables will also appear in this array but will disappear after developer finishes transaction.

Conclusion

In Apphud we implemented App Store receipt validation for apps with auto-renewable subscriptions in our open-source SDK. Besides that, Apphud helps to track subscriptions, analyze key metrics, grow your revenue by reducing voluntary and involuntary churn, etc. You can start using Apphud free.