Here’s a Node.js microservice that validates iTunes receipts

If you’re an app developer and you need to validate customers’ iTunes receipts, you’ll have to hit Apple’s API. This is especially important if your app contains subscriptions, which you’ll need to periodically check to see if they are still valid.

Unfortunately, the response JSON that Apple provides is kind of weird and bloated. For example, if a customer has a monthly renewable subscription, you’ll likely get back a bunch of objects, and you’ll need to find the latest one to properly validate their subscription.

I created a Node microservice, below, that will validate receipts and can be deployed to any cloud provider. I used Now, which is pretty awesome, by the way.

const { json } = require('micro')
const request = require('request')

module.exports = async (req, res) => {
	//get json payload, which contains receipt
	//i'm using micro, but you can use many things, like body-parser
	const reqData = await json(req);
	
	//create response object
	//status = request status from Apple
	//expired = is the subcription expired
	var respObj = { status: 0, expired: true, expiration: 0 }
	
	//hit Apple api for receipt data
	let promise = new Promise((resolve, reject) => { 
		var postData = { 'receipt-data':reqData.receipt, 'password':process.env.APP_SEC };
		request({
			url: 'https://buy.itunes.apple.com/verifyReceipt',
			method: 'POST',
			json: true,
			body: postData
		}, function (error, response, body){
			if (response.statusCode == 200) {
				resolve(validateResp(body, respObj));
			} else {
				reject('Error: ' + response.statusCode);
			}
		});
	});

	respObj = await promise;
	return respObj; 
}

var validateResp = function(body, respObj) {
	//if status is not 0, the receipt is not valid
	if (body.status > 0) {
		respObj.status = body.status;
		return respObj;
	}

	//handle multiple receipts from renewable subscriptions
	var nowMs = new Date().getMilliseconds();
	var receipts = body.receipt.in_app;
	var expirations = receipts.map(function(x) { return x.expires_date_ms });
	var expMs = expirations.reduce(function(x,y){ return (x>y) ? x:y });
	respObj.expiration = expMs;
	
	//check if expiration date is greater than current time
	if (expMs > nowMs) {
		respObj.expired = false;
	}

	return respObj;
}

Advertisements
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: