Welcome folks today in this blog post we will be integrating paytm payment gateway
integration in node.js and express
using javascript. All the full source code of the application is shown below.
Get Started
In order to get started you need to initialize a new node.js
project using the below command as shown below
npm init -y
npm i express
Directory Structure of App
Now we need to create the index.js
file and copy paste the following code
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
const express = require("express"); const https = require("https"); const qs = require("querystring"); const app = express(); const parseUrl = express.urlencoded({ extended: false }); const parseJson = express.json({ extended: false }); const PORT = process.env.PORT || 4000; app.get("/", (req, res) => { res.sendFile(__dirname + "/index.html"); }); app.post("/paynow", [parseUrl, parseJson], (req, res) => { // Route for making payment var paymentDetails = { amount: req.body.amount, customerId: req.body.name, customerEmail: req.body.email, customerPhone: req.body.phone, }; if ( !paymentDetails.amount || !paymentDetails.customerId || !paymentDetails.customerEmail || !paymentDetails.customerPhone ) { res.status(400).send("Payment failed"); } else { var params = {}; params["MID"] = config.PaytmConfig.mid; params["WEBSITE"] = config.PaytmConfig.website; params["CHANNEL_ID"] = "WEB"; params["INDUSTRY_TYPE_ID"] = "Retail"; params["ORDER_ID"] = "TEST_" + new Date().getTime(); params["CUST_ID"] = paymentDetails.customerId; params["TXN_AMOUNT"] = paymentDetails.amount; params["CALLBACK_URL"] = "http://localhost:3000/callback"; params["EMAIL"] = paymentDetails.customerEmail; params["MOBILE_NO"] = paymentDetails.customerPhone; checksum_lib.genchecksum( params, config.PaytmConfig.key, function (err, checksum) { var txn_url = "https://securegw-stage.paytm.in/theia/processTransaction"; // for staging // var txn_url = "https://securegw.paytm.in/theia/processTransaction"; // for production var form_fields = ""; for (var x in params) { form_fields += "<input type='hidden' name='" + x + "' value='" + params[x] + "' >"; } form_fields += "<input type='hidden' name='CHECKSUMHASH' value='" + checksum + "' >"; res.writeHead(200, { "Content-Type": "text/html" }); res.write( '<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Please do not refresh this page...</h1></center><form method="post" action="' + txn_url + '" name="f1">' + form_fields + '</form><script type="text/javascript">document.f1.submit();</script></body></html>' ); res.end(); } ); } }); app.post("/callback", (req, res) => { // Route for verifiying payment var body = ""; req.on("data", function (data) { body += data; }); req.on("end", function () { var html = ""; var post_data = qs.parse(body); // received params in callback console.log("Callback Response: ", post_data, "n"); // verify the checksum var checksumhash = post_data.CHECKSUMHASH; // delete post_data.CHECKSUMHASH; var result = checksum_lib.verifychecksum( post_data, config.PaytmConfig.key, checksumhash ); console.log("Checksum Result => ", result, "n"); // Send Server-to-Server request to verify Order Status var params = { MID: config.PaytmConfig.mid, ORDERID: post_data.ORDERID }; checksum_lib.genchecksum( params, config.PaytmConfig.key, function (err, checksum) { params.CHECKSUMHASH = checksum; post_data = "JsonData=" + JSON.stringify(params); var options = { hostname: "securegw-stage.paytm.in", // for staging // hostname: 'securegw.paytm.in', // for production port: 443, path: "/merchant-status/getTxnStatus", method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": post_data.length, }, }; // Set up the request var response = ""; var post_req = https.request(options, function (post_res) { post_res.on("data", function (chunk) { response += chunk; }); post_res.on("end", function () { console.log("S2S Response: ", response, "n"); var _result = JSON.parse(response); if (_result.STATUS == "TXN_SUCCESS") { res.send("payment sucess"); } else { res.send("payment failed"); } }); }); // post the data post_req.write(post_data); post_req.end(); } ); }); }); app.listen(PORT, () => { console.log(`App is listening on Port ${PORT}`); }); |
As you can see we have defined various routes
for generating the payment checksum
and also verifying the checksum and then loading the index.html
template file as shown below. Now we need to create the index.html
file
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <title>Paytm-Nodejs</title> </head> <body style="background-color:#f5f3ef"> <div class="row my-5"> <div class="col-md-4 offset-md-4"> <div class="card"> <div class="card-body"> <form class="" action="/paynow" method="post"> <div class="form-group"> <label for="">Name: </label> <input class="form-control" type="text" name="name" value=""> </div> <div class="form-group"> <label for="">Email: </label> <input class="form-control" type="text" name="email" value=""> </div> <div class="form-group"> <label for="">Phone: </label> <input class="form-control" type="text" name="phone" value=""> </div> <div class="form-group"> <label for="">Amount: </label> <input class="form-control" type="text" name="amount" value=""> </div> <div class="form-group"> <button class="btn form-control btn-primary">Pay Now</button> </div> </form> </div> </div> </div> </div> </body> </html> |
And now you need to make the Paytm
folder and inside it you need to create the checksum.js
file and copy paste the following code
Paytm/checksum.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
"use strict"; var crypt = require('./crypt'); var util = require('util'); var crypto = require('crypto'); //mandatory flag: when it set, only mandatory parameters are added to checksum function paramsToString(params, mandatoryflag) { var data = ''; var tempKeys = Object.keys(params); tempKeys.sort(); tempKeys.forEach(function (key) { var n = params[key].includes("REFUND"); var m = params[key].includes("|"); if(n == true ) { params[key] = ""; } if(m == true) { params[key] = ""; } if (key !== 'CHECKSUMHASH' ) { if (params[key] === 'null') params[key] = ''; if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) { data += (params[key] + '|'); } } }); return data; } function genchecksum(params, key, cb) { var data = paramsToString(params); crypt.gen_salt(4, function (err, salt) { var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex'); var check_sum = sha256 + salt; var encrypted = crypt.encrypt(check_sum, key); cb(undefined, encrypted); }); } function genchecksumbystring(params, key, cb) { crypt.gen_salt(4, function (err, salt) { var sha256 = crypto.createHash('sha256').update(params + '|' + salt).digest('hex'); var check_sum = sha256 + salt; var encrypted = crypt.encrypt(check_sum, key); var CHECKSUMHASH = encodeURIComponent(encrypted); CHECKSUMHASH = encrypted; cb(undefined, CHECKSUMHASH); }); } function verifychecksum(params, key, checksumhash) { var data = paramsToString(params, false); //TODO: after PG fix on thier side remove below two lines if (typeof checksumhash !== "undefined") { checksumhash = checksumhash.replace('n', ''); checksumhash = checksumhash.replace('r', ''); var temp = decodeURIComponent(checksumhash); var checksum = crypt.decrypt(temp, key); var salt = checksum.substr(checksum.length - 4); var sha256 = checksum.substr(0, checksum.length - 4); var hash = crypto.createHash('sha256').update(data + salt).digest('hex'); if (hash === sha256) { return true; } else { util.log("checksum is wrong"); return false; } } else { util.log("checksum not found"); return false; } } function verifychecksumbystring(params, key,checksumhash) { var checksum = crypt.decrypt(checksumhash, key); var salt = checksum.substr(checksum.length - 4); var sha256 = checksum.substr(0, checksum.length - 4); var hash = crypto.createHash('sha256').update(params + '|' + salt).digest('hex'); if (hash === sha256) { return true; } else { util.log("checksum is wrong"); return false; } } function genchecksumforrefund(params, key, cb) { var data = paramsToStringrefund(params); crypt.gen_salt(4, function (err, salt) { var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex'); var check_sum = sha256 + salt; var encrypted = crypt.encrypt(check_sum, key); params.CHECKSUM = encodeURIComponent(encrypted); cb(undefined, params); }); } function paramsToStringrefund(params, mandatoryflag) { var data = ''; var tempKeys = Object.keys(params); tempKeys.sort(); tempKeys.forEach(function (key) { var m = params[key].includes("|"); if(m == true) { params[key] = ""; } if (key !== 'CHECKSUMHASH' ) { if (params[key] === 'null') params[key] = ''; if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) { data += (params[key] + '|'); } } }); return data; } module.exports.genchecksum = genchecksum; module.exports.verifychecksum = verifychecksum; module.exports.verifychecksumbystring = verifychecksumbystring; module.exports.genchecksumbystring = genchecksumbystring; module.exports.genchecksumforrefund = genchecksumforrefund; |
And now we need to make the config.js
file inside the Paytm
folder as shown below
Paytm/config.js
1 2 3 4 5 6 |
var PaytmConfig = { mid: "####yourmid#####", key: "###yourkey#####", website: "##yourwebsite##", }; module.exports.PaytmConfig = PaytmConfig; |
And now you need to make the Crypt.js
file inside the Paytm folder and copy paste the following code
Crypt.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
"use strict"; var crypto = require('crypto'); var util = require('util'); var crypt = { iv: '@@@@&&&&####$$', encrypt: function (data,custom_key) { var iv = this.iv; var key = custom_key; var algo = '256'; switch (key.length) { case 16: algo = '128'; break; case 24: algo = '192'; break; case 32: algo = '256'; break; } var cipher = crypto.createCipheriv('AES-' + algo + '-CBC', key, iv); //var cipher = crypto.createCipher('aes256',key); var encrypted = cipher.update(data, 'binary', 'base64'); encrypted += cipher.final('base64'); return encrypted; }, decrypt: function (data,custom_key) { var iv = this.iv; var key = custom_key; var algo = '256'; switch (key.length) { case 16: algo = '128'; break; case 24: algo = '192'; break; case 32: algo = '256'; break; } var decipher = crypto.createDecipheriv('AES-' + algo + '-CBC', key, iv); var decrypted = decipher.update(data, 'base64', 'binary'); try { decrypted += decipher.final('binary'); } catch (e) { util.log(util.inspect(e)); } return decrypted; }, gen_salt: function (length, cb) { crypto.randomBytes((length * 3.0) / 4.0, function (err, buf) { var salt; if (!err) { salt = buf.toString("base64"); } //salt=Math.floor(Math.random()*8999)+1000; cb(err, salt); }); }, /* one way md5 hash with salt */ md5sum: function (salt, data) { return crypto.createHash('md5').update(salt + data).digest('hex'); }, sha256sum: function (salt, data) { return crypto.createHash('sha256').update(data + salt).digest('hex'); } }; module.exports = crypt; (function () { var i; function logsalt(err, salt) { if (!err) { console.log('salt is ' + salt); } } if (require.main === module) { var enc = crypt.encrypt('One97'); console.log('encrypted - ' + enc); console.log('decrypted - ' + crypt.decrypt(enc)); for (i = 0; i < 5; i++) { crypt.gen_salt(4, logsalt); } } }()); |