DEV Community

Cover image for How to Use Paystack's Webhooks in Node.js
Chiemezuo
Chiemezuo

Posted on • Edited on

How to Use Paystack's Webhooks in Node.js

This article assumes you are competent with Node.js, Git, and Github. It also assumes you have and can use an API-testing client like Insomnia or Postman.

Introduction

This is a guide on integrating payments via Paystack into your backend, using Node.js. I set up a bare-bones repo specifically for this tutorial, and you can check it out here. I intentionally made it as simple as possible, so you can focus on the main content, without needing to sift through folder structures. Now, let's get to the basics.

When a transaction is made via Paystack, there are two primary ways of knowing its completion status:

  1. Callback URLs.
  2. Webhook URLs.

To put it in simple words, a Webhook URL is just a URL or link. To put it in less simple words, a Webhook URL is a link that a service (in this case, Paystack) can send data to. The data it sends is an event that tells you (who owns that link), that the operation has been completed. An analogy of this is sending a letter to someone through the post office (initiating a transaction), and getting a letter from them mailed back to your address (a Webhook URL). With Webhooks, the only thing Paystack requires of you is that you send a 200 response code.

Callback URLs are a bit more direct but less versatile, and this article explains why.

Requirements

For this tutorial, aside from the requirements listed on the repo page, you will need a Paystack account set up. You'll also need a live backend service running with any host of your choice.

Note: You cannot use localhost for the Webhook URL.

Guide

To be on the same page, I recommend forking and cloning the repo here.
Steps:

  • After cloning the repo into your local machine, run the installation command for npm: npm install. This will install all the project dependencies.

  • Create a .env file. Do this by copying the content of the .env.example file and modifying it appropriately. Your .env file should end up with a similar-looking format:

PORT=3000 # port number
PAYSTACK_SECRET_KEY=<paystack_sk_test_key> # paystack secret key
Enter fullscreen mode Exit fullscreen mode

Note: Make sure you're using the test key for testing purposes, and not the production key.
To get your test key, this article will walk you through the process.

  • Now, let's examine the app.js file. An initializationUrl is defined for working with Paystack's API, and so are some very specific headers, as per Paystack's documentation.
const initializationUrl = 'https://api.paystack.co/transaction/initialize'
const headers = {
  Authorization: `BEARER ${process.env.PAYSTACK_SECRET_KEY}`,
  'Content-Type': 'application/json',
}
Enter fullscreen mode Exit fullscreen mode

There are two very important routes in the app.js file. The first one is for initiating a fund request. It takes in a payload consisting of an email and amount in a subunit of the supported currency. These are the only required parameters, but you can find a list of some additional optional parameters here.

app.post('/fund', async (req, res) => {
  const payload = {
    email: req.body.email,
    amount: req.body.amount
  }
// more code ...
Enter fullscreen mode Exit fullscreen mode

After the payload has been created, you send a request to the initializationUrl, passing it the payload, and the headers you defined. I recommend you incorporate error handling in case the request fails, to avoid server crashes and to be able to better identify issues. We would have something like this:

// ... payload data
try {
    const response = await axios.post(initializationUrl, payload, { headers })
    return res.status(201).json({ status: true, data: response.data })
} catch(e) {
    return res.status(400).json({ status: false, message: 'Funding failed' })
}
Enter fullscreen mode Exit fullscreen mode

Note: I used axios instead of fetch for simplicity, but the latter would still work just as fine.

We will be left with the second important route: the Webhook. The webhook only requires one thing from that route: a response of 200. However, accounting for the fact that you might want to do something or call a process when the Webhook is called, I added some boilerplate code. It gets the signature from the header that Paystack will pass along with the request, it compares the hash of the request body sent to you with the signature (using your secret key), and it leaves a little wiggle room for you if you are interested in adding some more logic if the hash matches the signature from the header.

// the Webhook for receiving Paystack's response
app.post('/paystack-webhook', async (req, res) => {
  const paystackSignature = req.headers['x-paystack-signature']
  const secret = process.env.PAYSTACK_SECRET_KEY

  const hash = crypto.createHmac('sha512', secret).update(JSON.stringify(req.body)).digest('hex')
  if (hash == paystackSignature) {

    // Retrieve the request's body
    const event = req.body
    // Do something with the event ...

    // You can log to the console to be sure
    console.log('The webhook was called with event:', event)
  }

  // A status response of 200 must be sent back to the Paystack 
  res.status(200).json({
    status: true,
    message: 'Received Paystack Event'
  });

})
Enter fullscreen mode Exit fullscreen mode
  • Deploy your backend service to any web host. Cyclic was a really good option for me.

  • After deploying, test that it's properly set up. To be sure the service is working properly, visit the base URL. For example; https://<your-url>/.
    You should see a "Welcome to the Paystack tutorial".
    If you do, the service is working fine.

  • With the service up and running properly, copy the URL to the Webhook, and add it to your Paystack account settings, under the 'API Keys and Webhooks' section.

    Note: Put this as the Webhook URL for test mode.

  • Now, for testing with an API client (Insomnia, in this case), you pass in a JSON payload to the fund route. This payload consists of your email and the amount in question.

{
    "email": "<your-mail>@mail.com",
    "amount": 2000
}
Enter fullscreen mode Exit fullscreen mode

If successful, you should get a response that looks like the snippets by the right side of this.

  • In the response you've received, there is an authorization_url. Open it to complete the transaction. On completing the transaction, you can close the browser page.

    Note: Since this is still test mode, trying to simulate a scenario where the transaction fails doesn't do anything.

  • Finally, you should go to the logs of your hosted application. Shortly after, you should see a logged statement indicating that the Webhook was called. You can also verify this by going to your Paystack dashboard and switching from live mode to test mode to see your most recent transaction.

That just about settles it, as far as working with Paystack's Webhooks is concerned.
Thank you for reading.

Cheers.

Top comments (0)