Skip to main content
In this tutorial we’re going to build a simple but feature complete Next JS application that lets your users view and take action against incoming payment requests that they have initiated using their payment alias. This tutorial is written from an issuer’s point of view and is relevant for any company that manages an account or wallet balance on behalf of their customers. There’s no database or other “production ready” things, so we can stay focused on Paylias. We expect this to take about 30 minutes if you’re following along, otherwise it’s a quick read so let get to it!

Setup

In our Next JS app that lets issuers surface pending tasks in the UI, and approve or reject them, we’ll use:
  1. A singleton in-memory DB
  2. ShadCN UI components
  3. Lucide icons
Scaffold your project
In-memory DB means data resets on restart. For production, swap in a real database.

Start the app

You should be able to open up http://localhost:3000 (or depending on your settings it should open up automatically) and see the default Next JS screen.

Folder structure

Next, you’re going to want to create a folder struture similar to this layout.
folder structure
The main thing to get right here are the files under the api/webhook folder. We’re going to opt for creating a separate route for each webhook event to keep a clear separation of concerns and since we’re using Next JS’s app based routing system, that means we need to create the following files
Once these files have been created, add this placeholder code in each file for now. Later on in this guide, we’ll update the ones relevant for an issuer.
Webhook POST handler

Signature Verification

Finally, we’ll add a helper function to validate the webhook signature from incoming events sent by Paylias. Open up the lib/signature.ts file and add in the following code.
signature.ts

Data Layer

Next up, we’ll define our basic data models to handle our internal representation of an incoming Payment Request, create a simple in-memory database and a repository layer that will let us perform our CRUD operations. Create a file under types called task.ts if you haven’t already done so and paste this inside
task.ts
Our task model will hold properties that are both internal to our issuer wallet app as well as properties from Paylias that identify an incoming Payment. In a production app, you can model this through database relations if required, but for now, we’ll focus on simplicity to get a working app integrated with Paylias. Next, we’ll define our in memory database as a simple class that manages a Map. Open up the database/memory-db.ts file (or create one if you haven’t) and add the following code inside
memory-db.ts
If you save your app, you may notice some build errors because the taskStore variable is not defined. Because we have chosen to use an in-memory database, in Next, (whether in dev with HMR or in production on Vercel’s serverless functions), the data in this module can be torn down and re-evaluated at any time, so tasks gets reset. In order to avoid this and truly get one bucket of memory to live across all imports (& HMR reloads) in a single Node process, you need to hang it on the Node “global”. So create a new file inside the database folder called global-db.ts and add this code
global-db.ts
And add an import to your memory-db.ts file to fix the compile errors.
memory-db.ts
As a last step for the data layer, we’ll define a simple TaskRepository that will allow us to manipulate tasks in the memory-db. So go ahead and open up the file repository/taskRepository.ts and add the following code inside.
taskRepository.ts

Webhook implementation

Now that we’ve set up the data layer, we’ll look into implementing the relevant webhooks required to build out our issuer app! If you haven’t already, we recommend going through the Webhook guides to get an understanding of what webhooks are and how they work. Once you’ve completed the guides, you can start implementing the webhooks for your issuer app. Since we’re opting to create an individual endpoint for each combination of record_type and event_type, the first step we have to complete is to create webhook subscriptions on Paylias for each endpoint. You can follow the Webhook Implementation guide to create the endpoint subscriptions on Paylias.
Since Paylias cannot deliver webhooks to localhost, we’re going to first have to expose our app through a tunnel. We recommend using ngrok. You may need to create a free account and install it on your system before proceeding further.

Side step

You can run this command in another terminal window to expose your app through ngrok to the internet.
You should see an output similar to this in your terminal
Copy the URL that ngrok has assigned to your local app and use that as the base url when creating webhook subscriptions for Paylias. For example, for each of your webhook endpoints defined in the app, the full URL that you need to use when creating the webhook subscriptions will be as follows
Using these endpoints, you can create webhook subscriptions using either the dashboard or the Create Webhook API.
Make sure you subscribe to the right combination of record_type and event_type for each endpoint on your app

Implementation

Now, we’ll implement only the four Paylias webhooks an Issuer needs
1

`payment-admission:created`

When Paylias notifies us that a new payment admission has been created, we will
  • Parse the payload to extract the relevant information
  • Validate the signature in the header
  • Create a new Task record in your database with the amount and currency in the payment and status PENDING
  • Add a placeholder to trigger any risk-check logic
  • Send a response back to Paylias to acknowledge receipt of the webhook
2

`payment-admission-task:created

When Paylias notifies us that a new payment admission task has been created, we will
  • Parse the payload to extract the relevant information
  • Validate the signature in the header
  • Look up the original task
  • Update the task to either PENDING or REJECTED
  • Send a response back to Paylias to acknowledge receipt of the webhook
3

payment-exception:created

If Paylias sends an event notifying us that there was an exception during the payment processing flow, we’ll update the task to REJECTED and save the error message.
4

payment-transaction:created

The final step in the payment journey is marking the payment complete. When you receive this event, the payment is considered as final and any deductions in the user’s balance and ledger updates should be made on your platform (preferably asynchronously so you can respond back to Paylias quickly). The Transaction Resource guide explains this in more details.

Front-End UI

Now that we’ve set up majority of the application at the backend, its time to move on to the frontend so that our users can see and respond to their payment requests. The general functionality we’re going to develop on the frontend will include
  • Displaying a list of all Tasks in a column view
  • Polling for all tasks in the background and updating the list
  • Taking action on PENDING tasks to allow our user to either accept or reject them.
This is a fairly simple UI/UX implementation meant for demostration purposes only. In your production application you would most likely use push notifications as new tasks come in to your system and have a separate notification page or tray to display any pending tasks to your user.
Lets get to it!

Install shad-cn components

First off, we’ll install the relevant Shad Cn components needed to build our UI. Open up a terminal window and cd into the root directory of your app. Once there copy-paste this command

Create components

Once these have been installed, add the following components under the components directory.

Fetch All Tasks

Now that we’ve created the basic components needed to display a Task, we’re going to create an endpoint that will return us a list of tasks for us to render in a list. Open up app/api/tasks/route.ts and add in the following code
route.ts
We’re going to use this endpoint in the following TasksList component to poll for all tasks every 5 seconds. Lets create the TasksList component now. Create a new file under components called TasksLists.tsx and add in the following code
TasksList.tsx
Lets put all of this together now. Open up app/page.tsx and replace the existing code with the following
page.tsx
When you refresh your browser, you should see your Navbar and under that a message that says “No tasks found that require any action.” Since we don’t have any tasks in our database, there’s nothing to display at the moment but that will change once we start receiving incoming payment requests. But lets assume our webhooks will work as expected and implement the functionality required to take action on a PENDING task.

Updating a task

Updating the task is a two step process. When our user clicks on a task they want to action on, we’ll open up a dialog that will first fetch the task along with its details from our database. Then, depending on whether they want to approve or reject the payment request, we’ll update the task accordingly and respond to Paylias with our decision. To make this work, lets first start with implementing the two endpoints we’re going to need. Open up the /api/tasks/[task-id]route.ts file and add in the code below to implement both the GET and PUT endpoints.
In our implementation of the PUT endpoint we’re also calling the Update Admission Task endpoint. You’ll notice that we’re not updating the task in our database yet. If we reject the task, Paylias will trigger an Exception event which our /api/webhook/payment-exception/created endpoint will catch. This is where our the task will be updated in our system. Similarly, if we approve the task, Paylias will trigger a Transaction event which our /api/webhook/payment-transaction/created endpoint will catch. This is where we will mark the task as COMPLETED. The final step in this guide is to implement the UI for updating a task. We’ll accomplish this using the <Dialog> component from Shad Cn along with implementing parallel and intercepting routes from Next JS. Create a new file under the components directory called UpdateTask.tsx and add in the following code
UpdateTask.tsx
Now that our client component is ready, we’ll wire it up to the rest of our app so its accessible through routing. Create the following folder structure under your app directory.
Now add the following code to the relevant files

Conclusion

That’s it! You’ve just implemented money-movement as an issuer for your customers. We’re grateful for giving Paylias a try and we hope this tutorial gives you a solid start to build great user experiences. There’s a lot more you can do like Creating namespaces, Issuing aliases and, if your use-case supports accepting payments, Integrating Paylias as an Acquirer. Be sure to check out our Api Reference and reach out at ziyad@paylias.xyz if you need any help!