Online receipt validation for Mac App Store In-App Purchases

My app EasyBooks provides an online component that users pay yearly for. It wouldn't make sense to provide this as a non-consumable type as it only really works as a consumable (however it's really a non-repeating subscription in iOS). I would like to offer this in-app and I think I have a solution finally...

I used one of my Apple DTS tickets to query a statement made in the StoreKitGuide document. It says ...

"OS X supports both the server validation method described in this chapter and the local validation method..."

I got a reply from Apple saying ...

"The steps for verifying your In-App Purchase products for Mac applications are the same used for iOS applications. The difference is that you will be assigning your base 64 encoded app receipt (rather than the content of the transactionReceipt property) to the receipt-data field. Retrieve the full Mac App Store receipt for your application, then encode it using base64 encoding. Create a JSON object with a single key named receipt-data and assign your encoded receipt to it. Proceed as outlined in the Verifying a Receipt with the App Store section of the In-App Purchase Programming Guide.

Note: In App Purchases receipt are included in the associated Mac app's receipt. You must check the receipt associated with your app to verify the validity of the In-App Purchase receipts that it contains. Doing so also allows you to enable the appropriate functionality in your app."

So after some failed attempts, I did manage to get this working with the caveat that the receipt data returned by Apple's servers does not contain the 'hash of the GUID' and therefore does not tie the receipt data to any particular hardware.

This can be tested on your Mac quite easily using these steps:

  1. Find the Mac app receipt file (it's in your app's bundle once you've run the app and entered your (test) Apple ID and password.

  2. At the command line, base64 -i receipt will base64 encode the receipt with no line breaks (that's important)

  3. Again at the command line, curl -d '{ "receipt-data": "<your b64 string here>" }' https://sandbox.itunes.apple.com/verifyReceipt

This returns JSON data in the format

{"status":0, 
 "environment":"Sandbox", 
 "receipt":{"adam_id":"0", 
            "bundle_id":"uk.co.geode.easybooks", 
            "application_version":"2.2.7", 
            "download_id":"0", 
            "in_app":[ {"quantity":"1", 
                        "product_id":"uk.co.geode.easybooks.syncing",
                        "transaction_id":"1000000034508678",
                        "purchase_date":"2012-09-05 12:00:17 Etc/GMT",
                        "original_transaction_id":"1000000034508678",
                        "original_purchase_date":"2012-01-24 10:16:17 Etc/GMT"} ]}}

I have not confirmed it yet, but apparently (according to the Apple engineer) any consumable types of in-app purchase will be added to the receipt when first purchased, but removed after any further purchases or restore operations. I wonder whether it might be a good idea to make the code running in the app make a copy of the receipt file after each purchase just in case our own servers are down at the time the app tries to validate the receipt. Users may otherwise try to restore purchases, not realising this will remove any consumable product receipts.

I hope that helps.

(ORIGINAL COMMENTS FOLLOW)

I have the same issue. I have an iOS app in the store that has a mix of consumable and non-consumable products that can be purchased in-app. The consumable product is a service, which is fulfilled by my webserver. In the StoreKit delegate method paymentQueue:updatedTransactions:, I use the transactionReceipt property, which is an NSData object. I encode this to base64 and send it to the server. Out on the server I pass the receipt to Apple's servers for validation.

But for Mac OS, there is no transactionReceipt property on the SKPaymentTransaction, so we cannot validate receipts in the same way.

We can do the non-consumable products, which may help you. When an in-app purchase is made on Mac OS, the receipt is updated in the app bundle. It is then possible to parse the receipt file looking for each in-app receipt, which are all stored in the receipt file in the main bundle. For more about that see http://developer.apple.com/library/mac/#releasenotes/General/ValidateAppStoreReceipt/_index.html

This works fine for me when I use the non-consumable product, but I have one consumable and this is not updated into the app's receipt file. Without the transactionReceipt property, I don't see any way for my server to validate that the receipt is genuine. If anyone else has any other experience please let us know!

Anyone with an Apple developer account can also read about this on the Apple developer forum: https://devforums.apple.com/message/548411#548411