How to Integrate Paytm Payment Gateway?

How to Integrate Paytm Payment Gateway?

·

8 min read

In this article, I will show you how to integrate Paytm Payment Gateway into your website or app using Node.js and Express. Paytm Payment Gateway is a secure and easy way to accept online payments from your customers. You can use Paytm Payment Gateway to accept payments from various sources, such as debit/credit cards, UPI, Netbanking, Paytm Wallet, and EMI. You can also benefit from the features and offers that Paytm Payment Gateway provides, such as high success rates, dedicated support, analytics, affordability products, and more

Github Code : here

Now just follow these steps:

Create a new folder and open it in VS Code.

  1. npm init -y (this will create package.json file)

  2. npm i express nodemon (this will install express and nodemon)

  3. Open the paytm website here a

Login with your paytm account

  • Go to Developer Settings

  • Click on API Keys

    or,

    • Go to here

    • Copy the Merchant ID and Merchant Key

  1. Change the script in package.json to "start": "nodemon index.js"

"scripts": { "start": "nodemon index.js" }, ``` 5. Create a file named index.js and paste the following code.

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}`);
});
  1. Create a file named index.html and paste the following code.
<!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>
  1. Hit npm start to start the server.
  • The browser will display a form "name email phone number.".

If you simple open the html file you will see in the form action is /paynow and method is post so it will send the data to the server and the server will send the data to the paytm server and the paytm server will send the response to the server and the server will send the response to the browser.

  1. And now you need to make the Paytm folder and inside it you need to create the checksum.js file and copy the following code

Paytm/checksum.js

"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;
  1. Now you need to create the config.js file inside the Paytm folder and copy the following code
var PaytmConfig = {
mid: "####yourmid#####",
key: "###yourkey#####",
website: "##yourwebsite##",
};
module.exports.PaytmConfig = PaytmConfig;

Note: You need to replace the mid and key with your own mid and key and website with your own website

  1. Now you need to create the crypt.js file inside the Paytm folder and copy the following code
"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);
  }
}

}());
  • Now if you enter the name and email and click on the Pay Now button you will be redirected to the Paytm payment gateway and you can pay using the Paytm app or using the Paytm website.