Skip to content

Commit 6190d9b

Browse files
Justin PageRon Korving
authored andcommitted
Support Amazon purchase verification (#29)
* Support for verifying Amazon receipts
1 parent d012756 commit 6190d9b

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

README.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var payment = {
2525
packageName: 'my.app',
2626
secret: 'password',
2727
subscription: true, // optional, if google play subscription
28+
userId: 'user id', // required, if amazon
2829
devToken: 'developer id' // required, if roku
2930
};
3031

@@ -38,6 +39,42 @@ the next chapter for more information on the format.
3839

3940
## Supported platforms
4041

42+
### Amazon
43+
44+
**The payment object**
45+
46+
The receipt string represents the transaction returned from a channel or product
47+
purchase.
48+
49+
A Shared secret and user ID is required.
50+
51+
**The response**
52+
53+
The response passed back to your callback will also be Amazon specific. The entire parsed receipt
54+
will be in the result object:
55+
56+
```json
57+
{
58+
"receipt": {
59+
"betaProduct": false,
60+
"cancelDate": null,
61+
"parentProductId": null,
62+
"productId": "com.amazon.iapsamplev2.gold_medal",
63+
"productType": "CONSUMABLE",
64+
"purchaseDate": 1399070221749,
65+
"quantity": 1,
66+
"receiptId": "wE1EG1gsEZI9q9UnI5YoZ2OxeoVKPdR5bvPMqyKQq5Y=:1:11",
67+
"renewalDate": null,
68+
"term": null,
69+
"termSku": null,
70+
"testTransaction": false
71+
},
72+
"transactionId": "wE1EG1gsEZI9q9UnI5YoZ2OxeoVKPdR5bvPMqyKQq5Y=:1:11",
73+
"productId": "com.amazon.iapsamplev2.gold_medal",
74+
"platform": "amazon"
75+
}
76+
```
77+
4178
### Apple
4279

4380
**The payment object**
@@ -212,6 +249,15 @@ MIT
212249

213250
## References
214251

252+
### Amazon References
253+
**Code Inspiration**
254+
255+
* https://github.com/may215/amazon_iap
256+
257+
**API Reference**
258+
259+
* https://developer.amazon.com/public/apis/earn/in-app-purchasing/docs-v2/verifying-receipts-in-iap
260+
215261
### Apple References
216262
**Code Inspiration**
217263

@@ -221,7 +267,6 @@ MIT
221267

222268
* https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
223269

224-
225270
### Google Play References
226271
**Code Inspiration**
227272

bin/verify-amazon.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env node
2+
3+
var argv = require('minimist')(process.argv.slice(2), { string: ['secret', 'userId', 'receipt'] });
4+
5+
if (argv.help) {
6+
console.log('Usage: ./verfiy.js --secret=\'shared-secret\' --userId=\'amazon-user\' --receipt=\'receipt-data\'');
7+
process.exit(1);
8+
}
9+
10+
var iap = require('../index.js');
11+
12+
var platform = 'amazon';
13+
var payment = argv;
14+
15+
iap.verifyPayment(platform, payment, function (error, result) {
16+
if (error) {
17+
return console.log(error);
18+
}
19+
20+
console.log('Verified:');
21+
console.log(JSON.stringify(result, null, '\t'));
22+
});

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var platforms = {
2+
amazon: require('./lib/amazon'),
23
apple: require('./lib/apple'),
34
google: require('./lib/google'),
45
roku: require('./lib/roku')

lib/amazon/index.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
var assert = require('assert');
2+
var https = require('../https');
3+
4+
var apiUrl = {
5+
production: 'https://appstore-sdk.amazon.com/version/1.0/verifyReceiptId/developer/'
6+
};
7+
8+
exports.verifyPayment = function (payment, cb) {
9+
try {
10+
assert.equal(typeof payment.secret, 'string', 'Shared secret must be a string');
11+
assert.equal(typeof payment.userId, 'string', 'User ID must be a string');
12+
assert.equal(typeof payment.receipt, 'string', 'Receipt must be a string');
13+
} catch (error) {
14+
return process.nextTick(function () {
15+
cb(error);
16+
});
17+
}
18+
19+
var requestUrl = apiUrl.production + payment.secret + '/user/' + payment.userId + '/receiptId/' + payment.receipt;
20+
21+
https.get(requestUrl, null, function (error, res, resultString) {
22+
if (error) {
23+
return cb(error);
24+
}
25+
26+
var resultObject = null;
27+
28+
try {
29+
resultObject = JSON.parse(resultString);
30+
} catch (error) {
31+
return cb(error);
32+
}
33+
34+
if (res.statusCode === 400) {
35+
return cb(new Error('receiptId is invalid, or no transaction was found for this receiptId'));
36+
}
37+
38+
if (res.statusCode === 496 ) {
39+
return cb(new Error('Invalid sharedSecret'));
40+
}
41+
42+
if (res.statusCode === 497) {
43+
return cb(new Error('Invalid User ID'));
44+
}
45+
46+
if (res.statusCode === 500) {
47+
return cb(new Error('There was an Internal Servor Error'));
48+
}
49+
50+
if (res.statusCode !== 200) {
51+
return cb(new Error('Unknown operation exception'));
52+
}
53+
54+
cb(null, {
55+
receipt: resultObject,
56+
transactionId: resultObject.receiptId,
57+
productId: resultObject.productId
58+
});
59+
});
60+
};

0 commit comments

Comments
 (0)