Payment Integration With Node.Js: Express, Request and Paystack API

Franklyn Ugege
BitHubPH
15 min readDec 4, 2018

--

A good number of website owners today need channels for online payment especially as the sector has grown in lips and bounds. In this article, we are going to take a trip to the world of online payment integration using Paystack API as a case study.

We would try to modularize the project structure to easily scale to incorporating other payment platforms.

Basically, payment platforms use almost the same replica process for accepting payments online. It starts with an initialization of a transaction and a redirect to the payment platform and finally back to your site with a response of success or failure.

So we are going to start with baby steps:

i. Setting up Node.js

ii. Installing the needed Node.js packages for the project

iii. Setting up the MongoDB database model using mongoose

iv. Building our own paystack payment module

v. Setting up express server: app.js

a. Views using pug template engine

b. Creating endpoints for payment and confirmation

c. Testing donations

C’est fini: it’s finished.

To fully comprehend this, we would be creating a donation payment system. It’s just a simple 2-page system with a donation and success or failure.

In the land of Node.js, and the time of online payments, the destiny of a Charity Company rests on the shoulders of a young programmer, named… YOU!

What you need to know?

But at this point I assume you are familiar with the basics of Node.js and MongoDB; that you have Node.js and MongoDB already installed. If you have issues setting up Node.js or MongoDB check out this article on Setting Up Node.js and MongoDB

You’ll also be required to have a Paystack account, its actually free. So head over to paystack.com to create and account. The unverified account is actually ok to follow up.

The only downside is that you wont be getting any real money. 😄

Let’s get started… 💃

Setting up Node.js

First we’ll set up Node.js

To do that we’ll create a directory for our donation platform on the desktop (I’m using a windows system). Let’s call it “online_payment”.

Open your CLI by searching for “cmd” from the start menu.

Run the following command to navigate to the “online_payment” directory created on the desktop:

cd desktop
cd online_payment

Next we’ll initialize node running npm init from the project directory on cli (Fill the desired details, but the defaults would do by just pressing “enter” each time and entering ‘yes’ for the final step)

npm init

Installing the needed packages for the project

Next let’s install the Node.js modules we’ll be using in this project:

  • express,
  • request,
  • body-parser,
  • pug,
  • mongoose.

Just run this line on the CLI from the root of the project directory. Don’t forget you’ll need internet connection to successfully install the packages. Smilez!!!

npm install express request body-parser pug mongoose --save

Yay!!! Way to go… 🍦

We’ll set up our directory structure next.

In the root of the online_payment directory create three directories

  • config,
  • models and
  • views directories.

We would also need an “app.js” file from which our webserver would be served. So, go ahead and create the “app.js” file in the root of the online_payment directory.

Guess that would do for now at least.

Setup the MongoDB database model using mongoose

Let’s set up our connection to the database. Go ahead and create a “mongoose.js” file in the config directory. It would hold the connection to the database using the mongoose module: a MongoDB database driver. Read more on how to set up Node.js and MongoDB

In the mongoose.js file, add the following code snippet to establish a connection our MongoDB database.

Firstly, we import the mongoose module installed in our project and stored it to a constant name ‘mongoose’.

Next, we create a connection to the MongoDB database ‘online_payment’ on our local machine on the port 27017.

Remember, with MongoDB we do not need to explicitly create a database. If our application is trying to persist some data to the database and it does not find it, it would create it first before inserting into it.

At the end, we export it so it can be used in other JavaScript files within our project.

const mongoose = require (‘mongoose’);mongoose.connect(‘mongodb://localhost:27017/online_payment’,{useNewUrlParser:true});module.exports = {mongoose}

Next we’ll setup our MongoDB model showing the structure of the data we would be storing based on the donations made.

Here we import that connection “mongoose” object created in the mongoose.js file. We then use that object to create a database schema: object showing the different fields required for our database and its properties.

const {mongoose} = require('./../config/mongoose');const donorSchema = new mongoose.Schema({full_name: {    type: String,    required: true,},email: {    type: String,    required: true,},amount: {    type: Number,    required: true,},reference: {    type: String,    required: true}});const Donor = mongoose.model('Donor', donorSchema);module.exports = {Donor}

Here we created a Scheme that shows the different fields that the “Donor” model would have for each transaction: “full_name” and “email” of the person making the donation, “amount” being donated and the “reference” id given by paystack that uniquely identifies the transaction.

We can always use the reference string to fetch details from paystack about the particular transaction at any point in time.

We finally create a mongoose model out of the schema and export it so it can be used in other JavaScript files of our project.

Nice job!!! 👍

Following through to this point.

Building our own payment module

Now we’ll move over to creating a user defined module that would handle all transactions with paystack. This is in a bit to make our code clean, well-structured and easy to maintain, it would also provide a structure that can be reusable and scalable to easily accommodate other payment platforms using the same structure as this module.

In this module we would have two basic functions: initializePayment() and verifyPayment(). These would be called in the endpoints that initializes donations and in the callback that verifies payment status on paystack.

We would be using the request module (a third party module we installed from npm) to make request to the payment gateways. Request is a module that makes it very easy to make http calls.

The first argument is either a url or an options object. The options object has only one required property: “url” while others are optional.

Paystack requires that the merchant‘s API key be passed in the request headers as authorization property. Every merchant has his/her own unique API key with paystack, it helps to tie payments to the right merchant. To access your own Paystack API key:

  • Login to your paystack account
  • Go to the settings section,
  • Click on the API keys and Webhooks tab
  • Copy your test secret key

Our module would be placed inside the config directory. It would be named paystack.js.

To create our paystack module, we are going to create an Immediately Invoked Function Expression (IIFE) that takes in the request object. First, we’ll create our IIFE wrapper.

const paystack = (request) => {    const MySecretKey = 'Bearer sk_test_xxxx';    // sk_test_xxxx to be replaced by your own secret key   const initializePayment = (form, mycallback) =>   }   const verifyPayment = (ref,mycallback) => {   }   return {initializePayment, verifyPayment};}

In this IIFE we are basically going to create two function constants: initializePayment() and verifyPayment().

initializePayment (): This function initializes a Paystack transaction which returns an authorization url or an error as the case may be. Its purpose is to initialize the transaction and return the response of the request to where it was called.

The request module we’ll be using here is designed to easily make http calls. It accepts a uri | url or an options object with a required uri | url property and a callback function.

Within the options we can set different request paramters. For this learning purpose we’ll keep it streamlined to our needs for Paystack endpoints.

Like I mentioned earlier, paystack requires the header authorization be set to the merchant’s secret key.

Let’s go ahead to create our own little piece of magic. 😉

Start by filling out the body of the initializePayment() as below:

const initializePayment = (form, mycallback) => {    const options = {        url : 'https://api.paystack.co/transaction/initialize',        headers : {            authorization: MySecretKey,            'content-type': 'application/json',            'cache-control': 'no-cache'        },       form
}
const callback = (error, response, body)=>{ return mycallback(error, body); } request.post(options,callback);}

If you look carefully, you’ll realize we have an options object with all the paramters for our request set:

  • url,
  • headers, and
  • the form object which will contain the full name, email, amount and other needed paramters for the actual transaction.

The next thing is callback function. Request callback gets 3 arguments:

i. Error when applicable,

ii. The response object and

iii. The response body

All our call back does is return the callback function (mycallback) passed into the initializePayment passing in the error and body from the request. mycallback would be well defined to run after initializePayment runs whenever we call it.

And finally we call the request.post() which is request convenience method to initialize a POST request; passing in the request options object and the request callback created just above.

With that, we are through with the initializePayment().

Just a little highlight on its usage. Whenever the initializePayment () is called, it expects the form object to be passed in as the first argument and a callback function as the second. The callback function should expect two arguments too: error where applicable and body.

From Paystack documentation, the initialize endpoint returns an authorization_url on success. This would be very useful to redirect the donor to Paystack platform to enter payment details.

Let’s move to the second function, verifyPayment(): this is almost a replica of the first except for a few differences like the http request method being get. By default the method is not set in the request being sent, ‘GET’ is the default.

A note on how the Paystack payment works, after payment on Paystack platform, the user is redirected to a callback url set on the merchant’s paystack settings page. It comes back with a query string of the transaction reference stored in the reference variable.

In this callback url endpoint, we will call the verifyPayment() and make a request to paystack with the reference returned. If the request was successful, it would return a large object of the transaction containing many information about the transaction, like the amount, date, reference, payment_type, metadata, etc.

We’ll just go ahead and take a nose dive into the codes: 😉

const verifyPayment = (ref, mycallback) => {
const options = {
url : 'https://api.paystack.co/transaction/verify/'+encodeURIComponent(ref ),
headers : {
authorization: MySecretKey,
'content-type': 'application/json',
'cache-control': 'no-cache'
}
}
const callback = (error, response, body)=>{
return mycallback(error, body);
}
request(options,callback);
}

If you look closely, the verifyPayment() is very similar to the initializePayment(). One of the notable difference is that in the url string we call the encodeURIComponent() passing in the reference.

And secondly we call the request method, with implies a ‘GET’ http request; passing in the options object and the callback like before.

Finally to wrap it all up we return these two methods initializePayment() and the verifyPayment() in the IIFE and export the IIFE so it can be accessed by other JavaScript files in our project.

Below is the full script for the paystack.js file.

const paystack = (request) => {    const MySecretKey = 'Bearer sk_test_xxxx';    //sk_test_xxxx to be replaced by your own secret key    const initializePayment = (form, mycallback) => {        const option = {            url : 'https://api.paystack.co/transaction/initialize',            headers : {                authorization: MySecretKey,                'content-type': 'application/json',                'cache-control': 'no-cache'           },           form        }        const callback = (error, response, body)=>{            return mycallback(error, body);        }        request.post(option,callback);    }    const verifyPayment = (ref,mycallback) => {        const option = {            url : 'https://api.paystack.co/transaction/verify/' + encodeURIComponent(ref),            headers : {                authorization: MySecretKey,                'content-type': 'application/json',                'cache-control': 'no-cache'           }        }        const callback = (error, response, body)=>{            return mycallback(error, body);        }        request(option,callback);    }    return {initializePayment, verifyPayment};}module.exports = paystack

Way to go!!! 😍

We on our final lap. Setting up our server and testing our routes.

Setting Up Express Server

Finally, we are at the point where we create our express server and out routes to test our payments.

We would start by importing the needed modules:

Third party modules:

  • express: used to create our web server so that it can be accessed via http
  • request: just as the name implies, used to make http requests to paystack api endpoints
  • body-parser: used to convert the http body into a json
  • pug: used as our templating engine for our views
  • lodash: used to easily manipulate objects and arrays

Built in modoule:

  • path: used to help manipulate paths easily

User defined modules:

  • Donor: mongoose model, for handling interactions with the database
  • Paystack: has user defined functions for accessing paystack api endpoints using request module
const express = require('express');const request = require('request');const bodyParser = require('body-parser');const pug = require('pug');const _ = require('lodash');const path = require('path');const {Donor} = require('./models/donor')const {initializePayment, verifyPayment} = require('./config/paystack')(request);

Next we’ll setup the express server by creating a port where our application can be listened, then create our express app and set some middleware along the way we’ll set up our view engine.

const port = process.env.PORT || 3000;

Sets a constant port equal to the environment PORT constant or 3000.

const app = express();

Create our express app.

app.use(bodyParser.json());app.use(bodyParser.urlencoded({extended: false}))

Set up our express app middleware to parse request body in objects in req.body of the requests.

app.use(express.static(path.join(__dirname, ‘public/’)));

Setting up the express app middleware to serve public files from the public folder like css and js

app.set(‘view engine’, pug);

Finally we set the app’s view engine to pug.

Yaay!!! Setup is complete. ✨ ✨ ✨

Now we go taking a stroll in the park… 💪

Nice work guys. We through. And I mean it.

Let’s set up our first route to serve the index.pug file. It’s just a html page that holds a donations form with fields for full name, email and amount that would be used to initialize a transaction with paystack.

For reason of complexity, I would not delve into much about templating. It’s pretty easy if you know about html, take a look at the repo here to see all about the views.

Our first route: GET/

app.get(‘/’,(req, res) => {res.render(‘index.pug’);});

But this wont be accessible until we call the listen() on our express app.

app.listen(port, () => {console.log(`App running on port ${port}`)});

Here we pass it the port variable we declared earlier and a callback function, notifying us when the server is live.

Now sit back and take a nice bottle of coke for a job well done. Nice guys. Isn’t it beautify to see what we’ve been putting together all along come to live.

Wait for it, this is just the cherry on the pie. Wait for the big fish…

The form in index.pug submits to ‘/paystack/pay’ route. Lets go ahead and create it. That’s where the real magic takes place.

app.post(‘/paystack/pay’, (req, res) => {    const form = _.pick(req.body,[‘amount’,’email’,’full_name’]);    form.metadata = {        full_name : form.full_name    }    form.amount *= 100;    initializePayment(form, (error, body)=>{        if(error){            //handle errors            console.log(error);            return;       }       response = JSON.parse(body);       res.redirect(response.data.authorization_url)    });});

We create the route as before, only this time its going to be a post route. We pass in the ‘url path’ followed by a callback function which receives the request and response object.

Basically this route just handles the form submission and calls the paystack initializePayment function we created in our paystack module. After which the response from the initializePayment() is handled: on success redirects to a receipt page or logs the error. You can handle the error case anyhow you please.

So lets step through the code one at a time:

We use the lodash object function pick() to select some of the fields (email, amount, full_name) from the body that was sent in our post request from the form submission.

const form = _.pick(req.body,[‘amount’,’email’,’full_name’]);

From the list Paystack only accepts email and amount for a once off payment, but provides another property to store our own defined properties for the payment transaction: metadata property.

Next we reassign the full_name to the metadata property of the form object to help secure the name on paystack.

form.metadata = {full_name : form.full_name}

The next thing we do is to convert the amount to kobo as paystack only accepts values in kobo. This is most likely due to precision errors that amount from division. Read more here on my response to a comment.

form.amount *= 100;

Finally we call our initializePayment() passing in our form object and our call back as we defined earlier in the paystack module.

If no error it converts the body of the response to a JavaScript object using the JSON.parse().

We then pick the authorization_url sent back by paystack and redirect the donor to paystack to enter payment details; calling redirect on the app response object.

res.redirect(response.data.authorization_url)

After the donor’s interaction with paystack, the donor is redirected back to our application. In order to handle this, paystack gives us the privilege to set the callback url after interaction with it. We can set this in our paystack dashboard. Head on to paystack and go to settings, then to the API keys and Webhook tab. Set it to the url below:

http://localhost:3000/paystack/callback

Let’s head on to create the new route. In this route is where we make use of the second paystack function we created verifyPayment().

After initializing the payment with paystack, the callback from paystack has some payloads, one of which is the reference. This is the unique id that is tied to every transaction made on paystack. We are basically going to use this reference to double check the transaction made.

app.get('/paystack/callback', (req,res) => {    const ref = req.query.reference;    verifyPayment(ref, (error,body)=>{        if(error){            //handle errors appropriately            console.log(error)            return res.redirect('/error');        }        response = JSON.parse(body);        const data = _.at(response.data, ['reference', 'amount','customer.email', 'metadata.full_name']);        [reference, amount, email, full_name] = data;        newDonor = {reference, amount, email, full_name}        const donor = new Donor(newDonor)        donor.save().then((donor)=>{            if(donor){                res.redirect('/receipt/'+donor._id);            }        }).catch((e)=>{            res.redirect('/error');        })    })});

Let’s walk through the lines of code.

We get the reference from the request object: req

const ref = req.query.reference;

We then call verifyPayment() passing in the reference and a callback as defined in our paystack module.

If there’s an error we handle it the way we please or in this case redirect to the “/error” route.

if(error){    //handle errors appropriately    console.log(error)    return res.redirect(‘/error’);}

If there’s no error, we collect the body of the returned response and parse it like before. It would be really nice to view the kind of data returned by paystack on verification; so console.log() the response and take a deep look at the details therein.

The final steps pick out some values: reference, email, amount and full_name from the response, bundle it into an array using the lodash at() function.

const data = _.at(response.data, [‘reference’, ‘amount’,’customer.email’, ‘metadata.full_name’]);

Next assign the values of the array to variables and make an object of the variables.

[reference, amount, email, full_name] = data;newDonor = {reference, amount, email, full_name}

Finally we create a Donor mongoose model object from the object just created and persist the data in the database using the save() and redirect the user to the receipt page if successful otherwise the error page.

The receipt route accepts a Donor object, of the donor that just made the payment. This would be displayed on the page, showing the name of the donor and the amount.

The final route in the project is the error route which just renders an error page.

Below is a full view of the final app.js file, you can also view the full project on github just follow this link.

const express = require('express');const request = require('request');const bodyParser = require('body-parser');const pug = require('pug');const _ = require('lodash');const path = require('path');const {Donor} = require('./models/donor')const {initializePayment, verifyPayment} = require('./config/paystack')(request);const port = process.env.PORT || 3000;const app = express();app.use(bodyParser.json());app.use(bodyParser.urlencoded({extended: false}))app.use(express.static(path.join(__dirname, 'public/')));app.set('view engine', pug);app.get('/',(req, res) => {    res.render('index.pug');});app.post('/paystack/pay', (req, res) => {    const form = _.pick(req.body,['amount','email','full_name']);    form.metadata = {        full_name : form.full_name    }    form.amount *= 100;    initializePayment(form, (error, body)=>{        if(error){            //handle errors            console.log(error);            return;        }        response = JSON.parse(body);        res.redirect(response.data.authorization_url)    });});app.get('/paystack/callback', (req,res) => {    const ref = req.query.reference;    verifyPayment(ref, (error,body)=>{        if(error){            //handle errors appropriately            console.log(error)            return res.redirect('/error');        }        response = JSON.parse(body);        const data = _.at(response.data, ['reference', 'amount','customer.email', 'metadata.full_name']);        [reference, amount, email, full_name] =  data;        newDonor = {reference, amount, email, full_name}        const donor = new Donor(newDonor)        donor.save().then((donor)=>{            if(!donor){                res.redirect('/error');            }
res.redirect('/receipt/'+donor._id);
}).catch((e)=>{ res.redirect('/error'); }); });});app.get('/receipt/:id', (req, res)=>{ const id = req.params.id; Donor.findById(id).then((donor)=>{ if(!donor){ //handle error when the donor is not found res.redirect('/error') } res.render('success.pug',{donor}); }).catch((e)=>{ res.redirect('/error') });});app.get('/error', (req, res)=>{ res.render('error.pug');});app.listen(port, () => {console.log(`App running on port ${port}`)});

I hope I was able to share something helpful with you on integrating online payments using Node.js, Mongoose with Paystack API.

Finally, lets test our work.

Don’t forget to replace your secret keys in paystack.js with the one from your paystack account as requested earlier.

  1. On the root of your project directory on the CLI run:
node app

to start up the node application.

2. Open your favourite editor and enter the following url:

http://localhost:3000/

3. Fill the form as you wish:

The home route of the application.

3. On clicking the donate button, you’ll be redirected to Paystack to enter your card/payment details as below:

Use a test card to finish payment.

4. You’ll be redirected to the success page afterwards.

Success page

Love to hear your comments, feel free to leave a comment below. Follow us for more of such productive hands on tutorials on pressing ideas around web development.

Download the project from github here.

Subscribe to our youtube channel 🤓

--

--

Franklyn Ugege
BitHubPH

I am a fullstack developer with extensive experience in Javascript and Python and a passion for building highly configurable and user-friendly applications