Verifying The Purchase (Receipt) of Another Application (Mac App Store)

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

iOS verify app store purchase id by developer

Read Verifying Store Receipts in the In-App Purchase Programming Guide. According to the documentation:

To verify the receipt, perform the following steps:

  1. Retrieve the receipt data. On iOS, this is the value of the transaction's transactionReceipt property. On OS X, this is the entire contents of the receipt file inside the application bundle. Encode the receipt data using base64 encoding.

  2. Create a JSON object with a single key named receipt-data and the string you created in step 1. Your JSON code should look like this:

    {
    "receipt-data" : "(receipt bytes here)"
    }
  3. Post the JSON object to the App Store using an HTTP POST request. The URL for the store is https://buy.itunes.apple.com/verifyReceipt.

  4. The response received from the App Store is a JSON object with two keys, status and receipt. It should look something like this:

    {
    "status" : 0,
    "receipt" : { (receipt here) }
    }

If the value of the status key is 0, this is a valid receipt. If the value is anything other than 0, this receipt is invalid.

Read the article for more details.

Verify consumable in-app purchase for Mac OS X on server side

I was able to talk to an Apple rep about this issue. They basically said there is no way to verify a consumable receipt on the server in the current version of their framework.

How to verify a App Store Order ID received from a buyer's Apple receipt email?

Trust me there are no ways to link the data you have stored in your DB against email data (MKQHK4Y9LF) you received from User.

Using verify purchase you get original txn Id and other details but not the Id sent in Email. Apple considers that a PI.

The only way to get to know that is the userID, with each txn(subscription) you must be(should be) storing user id (emailID).

There should be a mapping of userID (email, guid etc) and original_transaction_id

What url should I use to verify my receipt in In-App Purchase

the best way is to first verify with the production server. if you get a 21007 code back you should make another call to the sandbox server. this is needed because during the submission process you're not always sure whether they'll use the live or sandbox server. it needs to work on both.

here's some source code that verifies receipts in safe way (counters the app store hack from last year). i added the above code to this project that will first check with the production server and then fall back to the sandbox server:

https://github.com/evands/iap_validation

EDIT: i wouldn't use that code above anymore in iOS 7. i think there are some problems with it!

AppStore in-App Purchase Receipt Verification Issues

If I read the documentation correctly, you're on the wrong track. The receipt that you send for verification is that chunk of data returned by the transactionReceipt property. You shouldn't care what it decodes to, or if it decodes to anything at all. You just base64-encode it, put it into a json object as the value for a key "receipt-data", and post that json object to Apple.

When you get the response back from Apple, that is what is supposed to contain the receipt data in json format.

Is it necessary to validate / refresh an app store receipt on launch in iOS?

you don't need to do so, that is optional only and could be done on iOS7+, if you interested in doing that.

briefly, implementing the validation is purely a financial decision, and even if you validate recipes you are recommended not to disable the content in case of failure as the validation could fail in standard environment as well anytime (e.g. in case of no connection), and such overreaction may ruin your consumers' experience.


altogether, doing the validation'd rather make sense on OSX in practice when you are allowed to disable the content in case of failure, regardless the reason; but if you feel you have more consumers than your income suggests or the amount of the stolen content is way beyond your margin, it may be worth to do it on iOS as well.


NOTE: in general you can read more about the technical details of receipt validation in Apple's Documentation.



Related Topics



Leave a reply



Submit