Integrating PayMongo API in Next.js - Part 2
Tags: nextjs, paymongo, javascript
Published: 2022-01-03 05:34:09

## Hi there,

In this two part article, I'll be guiding you on how to integrate the [PayMongo API](https://developers.paymongo.com/docs) in NextJS

In [Part 1](https://dev.to/xunylpay/integrating-paymongo-api-in-nextjs-part-1-1ee5), we have a brief discussion on PayMongo payment workflows and how to setup credit card payments.

In [Part 2](https://dev.to/xunylpay/integrating-paymongo-api-in-nextjs-part-2-3o5f), we tackle using webhooks to monitor payments and we move forward to processing GrabPay and GCash Payments. 


## Table of Contents
- [Introduction](#introduction)
  * [Demo](#demo)
  * [Webhooks](#webhooks)
- [Let's Code](#let-s-code)
  * [Setting Up](#setting-up)
  * [Running the project](#running-the-project)
  * [Creating an endpoint for the webhook](#creating-an-endpoint-for-the-webhook)
  * [Creating the webhook](#creating-the-webhook)
  * [Testing the webhook](#testing-the-webhook)
  * [Accepting E-wallet Payments (GCash and GrabPay)](#accepting-e-wallet-payments--gcash-and-grabpay-)
     + [Create a source](#create-a-source)
     + [Have the customer authorize the payment](#have-the-customer-authorize-the-payment)
     + [Create a Payment using the chargeable Source](#create-a-payment-using-the-chargeable-source)
- [Conclusion](#conclusion)



## Introduction
This is a simple guide for developers to integrate the PayMongo API in NextJS. Here, we'll start with a simple checkout and payment template project, and then move forward by filling up the API calls necessary to process payments. 

**PayMongo** provides businesses an easy, user-friendly way to accept payments from their customers. It is a payment gateway that process Visa/Mastercard, GCash, and GrabPay payments. 

**PayMongo API** is for those who want to directly integrate their site or app with PayMongo. Using the API allows you to take full control of the user's experience and integrate the payments directly with your systems and databases.

**ngrok** is a free service that helps you share a site or server running on your local machine



### Demo
**Live Preview:** https://nextjs-paymongo-api.vercel.app/
**GitHub:** https://github.com/xunylpay/nextjs-paymongo-api



### Webhooks
PayMongo provides webhooks that notify you of events happening during the payment process. Webhooks are a sure fire way to track payments especially if you want to store payment statuses in the database. Listening to events in the front end may result to consistency/reliability issues in your system (eg. client connection is cut, client closes the window after payment).  


## Let's Code

### Setting Up
In setting up, we assume that you have already finished doing the first part of this tutorial. Feel free to download or clone the [part-1-done branch](https://github.com/xunylpay/nextjs-paymongo-api/tree/part-1-done) in the repository. 

If you have not done so, create a .env file on the root folder. Insert your public and secret keys in this format: 

```
NEXT_PUBLIC_PAYMONGO_PUBLIC=pk_test_xxxxxxxxxxxxxxxxxxxxxxxx
PAYMONGO_SECRET=sk_test_xxxxxxxxxxxxxxxxxxxxxxxx
```
* The `NEXT_PUBLIC_` is important when exposing the environment variable in the front end

We also need `ngrok` to test our webhook endpoint locally.
```
yarn add ngrok --dev
```

Let's also set up our package.json script so we can start our ngrok tunnel.
`package.json`
```json
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "ngrok": "ngrok http 3000"
 },
```


### Running the project
Now open the project in your favorite text editor or IDE (Integrated Development Environment). Open a terminal then run the following commands to start up the development server. 

```
yarn
yarn dev
```

On localhost:3000 you should be seeing this: 

![localhost:3000 home](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/543fgp56pu6zfafci8pt.png)

On a different terminal, let's start our ngrok tunnel. 
```
yarn ngrok

or

ngrok http 3000
```

On your terminal, you should be seeing something like this: 
![Ngrok Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7311s1foh30m4085p8ew.png)

Take note of your forwarding address. In the case above, it is https://0f99-136-158-3-235.ngrok.io


### Creating an endpoint for the webhook
We need to create an endpoint in our site wherein PayMongo will make a post request to. In Next.JS, it's as easy as creating a file under the `pages/api` folder. For now, let's fill up the `pages/api/paymongo_webhook.js` with an endpoint that prints out the request PayMongo sends us for testing.

`pages/api/paymongo_webhook.js`
```javascript
// Webhook for paymongo payments

const handler = async (req, res) => {
  if (req.method === "POST") {
    console.log("===Webhook triggered===")
    const data = req.body.data
    console.log(data)
    console.log("===webhook end===")
    res.status(200).send("Webhook Received")
  }
  else {
    res.setHeader("Allow", "POST");
    res.status(405).send("Method Not Allowed");
  }
};

export default handler;
```

Let's test this out by creating a webhook and listening to a credit card payment. 

### Creating the webhook
We can easily create a webhook with PayMongo's [Create a webhook API Reference](https://developers.paymongo.com/reference/create-a-webhook). Enter your secret key in the username, enter your ngrok url + /api/paymongo_webhook in the url field (eg. `https://4566-49-145-8-183.ngrok.io/api/paymongo_webhook`), enter `source.chargeable`, `payment.paid` and `payment.failed` in the events field and click on "Try It". You can also use curl in doing this but doing it on the site is, personally, more hassle free. 

![Create a webhook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wynd0qc8v6flxezivq5.png)

This would create a webhook that you can use. Remember to list down your webhook ID, you can do it in a text file inside your project or add it in the `.env` file . 

You can also do the following in the API Reference: 
- [List your webhooks](https://developers.paymongo.com/reference/list-all-webhooks)
- [Update your webhooks](https://developers.paymongo.com/reference/update-a-webhook)
- [Disable your webhooks](https://developers.paymongo.com/reference/disable-a-webhook)

Do take note that every time you start your ngrok tunnel, it will give you a different url. You would have to [update your webhook](https://developers.paymongo.com/reference/update-a-webhook) when the url changes. 

### Testing the webhook
You can now test out your webhook that we have just finished setting up. In `localhost:8000`, make a successful card payment. It might take a couple of seconds to reach your ngrok tunnel but it should log a post request and a console log. The console log contains what the payload looks like. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ferlf7y9zrpo6gput3aj.png)

If you are not receiving any events after a couple of seconds, make sure that your webhook configurations are correct such as the url end point and the events array. 

There are 3 different webhook events that we are listening to:

1. source.chargeable - when an e-wallet payment has been authorized by the client
2. payment.paid - when a card/PayMaya/GCash/GrabPay payment is successful
3. payment.failed - when a card/PayMaya payment fails

### Accepting E-wallet Payments (GCash and GrabPay)
Now that we finished setting up our initial webhook end point, let's start accepting GCash and GrabPay. As mentioned in the first part of the tutorial, PayMongo uses the Source and Payment workflow to process GCash and GrabPay payments. Let's follow these steps as stated in the guide: 

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Create a Source
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Have the customer authorize the payment
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Create a Payment using the chargeable Source

Let's edit the `src/components/payments/GCash.js` and `src/components/payments/GrabPay.js`

#### Create a source
In both the e-wallet component files, I've already created a function called createSource. Let's fill up both of these functions and call the [Create a Source API](https://developers.paymongo.com/reference/create-a-source). 

```javascript
// In src/components/payments/GCash.js
// Function to Create A Source
  const createSource = async () => {
    setPaymentStatus("Creating Source")
    const options = {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Basic ${Buffer.from(publicKey).toString("base64")}`
      },
      body: JSON.stringify({
        data: {
          attributes: {
            amount: amount * 100,
            redirect: { success: 'http://localhost:3000/payment', failed: 'http://localhost:3000/payment' },
            billing: { name: `${name}`, phone: `${phone}`, email: `${email}` },
            type: 'gcash', //change to graby_pay in GrabPay.js
            currency: 'PHP'
          }
        }
      })
    }
    return fetch('https://api.paymongo.com/v1/sources', options)
      .then(response => response.json())
      .then(response => {
        return response
      })
      .catch(err => console.error(err));
  }

```

We can also create a front-end function to listen to the status of our payment source. We can use the [Retrieve a Source API](https://developers.paymongo.com/reference/retrieve-a-source) call for this. 
In `src/components/payments/GCash.js` and `src/components/payments/GrabPay.js`

```javascript
// Function to Listen to the Source in the Front End
  const listenToPayment = async (sourceId) => {
    let i = 5;
    for (let i = 5; i > 0; i--) {
      setPaymentStatus(`Listening to Payment in ${i}`)
      await new Promise(resolve => setTimeout(resolve, 1000))

      if (i == 1) {
        const sourceData = await fetch(
          'https://api.paymongo.com/v1/sources/' + sourceId,
          {
            headers: {
              // Base64 encoded public PayMongo API key.
              Authorization: `Basic ${Buffer.from(publicKey).toString("base64")}`
            }
          }
        ).then((response) => {
          return response.json()
        }).then((response) => {
          console.log(response.data)
          return response.data
        })

        if (sourceData.attributes.status === "failed") {
          setPaymentStatus("Payment Failed")
        }
        else if (sourceData.attributes.status === "paid") {
          setPaymentStatus("Payment Success")
        }
        else {
          i = 5;
          setPayProcess(sourceData.attributes.status)
        }
      }
    }
  }
```

Let's test this out by calling the two functions we made in our onSubmit function.

In `src/components/payments/GCash.js` and `src/components/payments/GrabPay.js`

```javascript
const onSubmit = async (event) => {
     event.preventDefault();
    const source = await createSource();
    window.open(
      source.data.attributes.redirect.checkout_url, "_blank");
    listenToPayment(source.data.id)
  };
```
 

#### Have the customer authorize the payment
After creating the source and opening the checkout_url, we can simulate how a customer will authorize the payment. 
![Authorize GCash Payment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9qfy537tuwknu24psof3.png)

Here we can observe that: 
- If the customer **fails** the payment, the source status stays at **pending**.
- If the customer **cancels** the payment, the source status becomes **cancelled**
- If the customer **authorizes** the payment, the source becomes **chargeable**.

Keep in mind that even if a source becomes chargeable, this does not mean that the payment is already successful. You still need to create a payment for the chargeable source. If you fail to do this after an hour, PayMongo would return the funds back to the customer's e-wallet and the status would become cancelled ([see more](https://developers.paymongo.com/docs/accepting-gcash-payments#4-create-a-payment-using-the-chargeable-source)). As you may have noticed, we'll also be able to see changes to our source on our webhook having the events source.chargeable and payment.failed. 

#### Create a Payment using the chargeable Source
Theoretically, you could create a payment after listening in the front-end; however, it is not advisable. End users might close the window or lose internet connection so it is better to create the payment on webhooks. 

Let's edit our `src/pages/api/paymongo_webhook.js` to handle this for us and call the [Create a Payment](https://developers.paymongo.com/reference/create-a-payment) API. Let us separate each event with an if-else statement.
 
In `src/pages/api/paymongo_webhook.js`
```javascript
const handler = async (req, res) => {
  if (req.method === "POST") {
    console.log("===Webhook triggered===")
    const data = req.body.data
    console.log(data)
    console.log("===webhook end===")
    if (data.attributes.type === "source.chargeable") {
      // Gcash and Grab Pay
      console.log("E-wallet Payment Chargeable")

    }
    if (data.attributes.type === "payment.paid") {
      // All Payment Types
      // Add next steps for you
      console.log("Payment Paid")
    }
    if (data.attributes.type === "payment.failed") {
      // Failed Payments - Cards Paymaya
      // Add next steps for you
      console.log("Payment Failed")
    }
    res.status(200).send("Webhook Received")
  }
  else {
    res.setHeader("Allow", "POST");
    res.status(405).send("Method Not Allowed");
  }
};

export default handler;
```

Here, you can also do the your next steps after listening to the event. A great example of this is updating your checkout link or your transactions table in a database. 

After separating our webhook events, let's [create a payment](https://developers.paymongo.com/reference/create-a-payment) every time a source becomes chargeable. 

In `src/pages/api/paymongo_webhook.js`
```javascript
...
    if (data.attributes.type === "source.chargeable") {
      // Gcash and Grab Pay
      console.log("E-wallet Payment Chargeable")

      // Create a payment resource
      const options = {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
          Authorization: `Basic ${Buffer.from(
            process.env.PAYMONGO_SECRET
          ).toString("base64")}`,
        },
        body: JSON.stringify({
          data: {
            attributes: {
              amount: data.attributes.data.attributes.amount,
              source: { id: `${data.attributes.data.id}`, type: `${data.attributes.data.type}` },
              description: data.attributes.data.attributes.description,
              currency: 'PHP',
              statement_descriptor: data.attributes.data.attributes.statement_descriptor
            }
          }
        })
      };

      fetch('https://api.paymongo.com/v1/payments', options)
        .then(response => response.json())
        .then(response => console.log(response))
        .catch(err => console.error(err));

    }
...
```

After doing so, we should now be able to accept e-wallet payments successfully. The webhook would log a source.chargeable event and then log a payment.paid event. 

## Conclusion
In this guide, you learned how to use PayMongo webhooks and accepting GrabPay and GCash Payments. This concludes the two part series and I hope you like this article and feel free to give feedbacks on my writing.