Apple Receipt Verification & Validation

The receipt verification service accepts your App's binary receipt data and returns a JSON object according to Apple's Receipt Validation Programming Guide.

URL Endpoint

This must be called with an HTTP Post

https://receiptverify.ikonetics.com/api

 

Attributes

receipt
binary

Required. The binary iOS in-app purchase receipt.

apikey
string

Required. Your account API access key is available on your account screen. It is a unique identifier for your account. We use Google to authenticate you and offer free accounts to all.

token
string

Required. The identifier for one of the Apps configured on your account screen. The receipt details will be compared to the bundle ID of the App as part of the validation process.


 

Returned JSON Properties

receipt

Optional. The decoded receipt returned directly from Apple. This field will not be returned when the result is an error. Always check the status property.

status

For all successful queries this will be 0.

If there are issues with your request this will contain one of the following status codes.
401   - Authentication is incorrect. Check the API key and App token matches your account.
403   - The receipt bundle does not match the App bundle. This receipt is not for this app. This might indicate an invalid receipt is being used to unlock in-app features.
501   - The server did not understand what you were trying to do. Check all of your parameters.

If Apple has an issue with the receipt provided you will receive one of Apple's status code. Apple's Receipt Validation Programming Guide provides a full list of values.

description

Human readable description of the status code. For example, Apple's code 21002 indicates the binary receipt data you provided was malformed or missing.


 

Sample JSON receipt result

A valid Apple receipt will be similar to the one below. Yours will probably be much larger with more complex items.

{
  "receipt": {
    "original_purchase_date_pst": "2012-04-30 08:05:55 America/Los_Angeles",
    "original_transaction_id": "10000000478817",
    "original_purchase_date_ms": "1335098354868",
    "transaction_id": "10000000478817",
    "quantity": "1",
    "product_id": "tld.ikonetics.AppName.InAppFeature",
    "bvrs": "20140427",
    "purchase_date_ms": "1335098355868",
    "purchase_date": "2014-04-30 15:05:55 Etc/GMT",
    "original_purchase_date": "2014-04-30 15:05:55 Etc/GMT",
    "purchase_date_pst": "2014-04-30 08:05:55 America/Los_Angeles",
    "bid": "tld.ikonetics.AppName",
    "item_id": "921129812"
  },
  "status": 0,
  "description": "Receipt valid",
}
	  	

The following JSON example shows the result returned when supplying invalid attributes. Notice the error result does not include the receipt.

{
  "status": 400,
  "description": "Parameter validation error",
}
	  	

 

Example iOS Code

This code should be used when your App is responding to transaction statuses, specifically after the SKPaymentTransactionStatePurchased status. More information is available on Apple's In-App Purchase Programming Guide .

The lines marked with TODO indicate areas where you may want to add custom code to handle your specific situation.

// You should NOT call this in a loop.
// Rather this should be called after you loop through all pending transactions.

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

if (!receipt) {
  // TODO: invalid receipt, stop and do error handling
}

// Configure a POST request with the receipt data.
NSURL *apiURL = [NSURL URLWithString:@"https://receiptverify.ikonetics.com/api"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:apiURL];

[request setHTTPMethod:@"POST"];
[request setHTTPBody:[receipt base64EncodedStringWithOptions:0]];


// Make the connection to the Receipt Verification service.
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response,
                                                  NSData *data,
                                                 NSError *connectionError) {

  if (connectionError) {
    // TODO: stop and do error handling
    NSLog(@"connection error:\n%@", connectionError);
  }
	
  NSError *error;
  NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
                                                       options:0
                                                         error:&error];
  if (!json) {
    // TODO: stop and do error handling
    NSLog(@"JSON parse error: %@", error);
  }


    // TODO: check that the receipt matches your App
    // the next example below shows how to compare the
    // JSON product_id an SKPaymentTransaction's productIdentifier
}
		

After you receive the JSON receipt your code should perform some simple checks to verify the JSON receipt from Apple matches your App and your In-App products. For example you may want to compare the transaction's productIdentifier to the product_id in the JSON receipt. Read the Apple documentation to learn other fields you might want to verify before unlocking features.

Assuming you have the productIdentifier from an SKPaymentTransaction and you have a method named unlockFeature, your code may look something like this:

NSDictionary *latest = [json objectForKey:@"latest_receipt_info"];

for (NSDictionary *lineitem in latest) {

  NSString *receiptItem = [lineitem objectForKey:@"product_id"];
  if ([productIdentifier isEqualToString:receiptItem]) {
    [self unlockFeature:lineitem];
  }
  
}