Implementing a crypto payment gateway using NodeJS
--
Considering the growth of the general interest in cryptocurrencies over the past few years, I wasn’t surprised when I one day decided to implement a crypto (specifically Bitcoin, Ether, and Litecoin — more on that later) paywall on one of my websites. Whether you believe it to be the “new big thing” or “just a fad”, learning how to work with and implement new technologies is always interesting (and necessary to stay relevant as a developer). The code is available at GitHub.
Coinbase Commerce API integration
In this article I will walk through the necessary steps to implement your crypto payment gateway, thus enabling you to take payments for your products/services in your preferred cryptocurrencies. This will be done using the Coinbase Commerce API — however, this article is in no way, shape, or form sponsored by them (I wish though, haha). Let’s move on.
Step 1: Create a Coinbase Commerce account
The first step is creating a Coinbase Commerce account, which can be done here. After you’ve created your account, head over to Settings > API Keys (scroll down), and generate an API key. We will need it for later integration. After you’re done it should look something like this:
Step 2: Initialize back-end
In this project, I will use NodeJS as the backend. Navigate to your programming folder and start your project using npm init:
mkdir crypto-checkoutcd crypto-checkoutnpm init
After you’ve initialized the project, create an index.js file — given that this is a rather small project, the majority of our code will go here.
Step 3: Installing the necessary packages
We will need a few packages to start. Install them using the following commands:
npm install expressnpm install coinbase-commerce-nodenpm install dotenvnpm install body-parser
Step 4: Set up environment variables
Before we jump into the index.js file, let’s set up our environment variables. Create a .env file in the root directory using the following command:
nano .env
You’ll enter an editor within your terminal window, where you should type the following:
PORT=3000
API_KEY=YOUR-API-KEY
Insert the API key you generated in step (1) and then exit the editor using ctrl+x and then press the ‘y’-key.
Step 5: Requiring the dependencies
Navigate over to your index.js file and open it using your IDE of choice. Firstly, require the packages we installed before:
// Importsconst express = require('express');const coinbase = require('coinbase-commerce-node');const dotenv = require('dotenv').config();const bodyParser = require('body-parser');
Before we continue: all this code can be found on GitHub. Moving along, let’s initialize the app instance to get the server running:
// App setupconst app = express();let server = app.listen(process.env.PORT, () => { console.log('Listening on port ' + process.env.PORT);});app.use(bodyParser.json());
If you’ve used express before this is hopefully familiar. If not, what this code does is serve our application on localhost:3000 (the ‘process.env.PORT’ carries the value 3000, defined in step (4)).
Lastly, we need to initialize the Coinbase Commerce client:
// Coinbase setupconst Client = coinbase.Client;Client.init(process.env.API_KEY);const Charge = coinbase.resources.Charge;
Like the port number, process.env.API_KEY carries the API key entered in step (4). I will get into the specifics of what the Client and Charge will be used for in later steps.
Step 6: Create charge route
We need to implement an endpoint, a URL, where we can create a Charge, a thing sort of equivalent to a “payment request.” Using the npm package making a charge request is quite easy:
app.post('/charge', (req, res) => { let chargeData = { name: req.body.name, description: req.body.decription, local_price: { amount: req.body.amount, currency: 'USD' }, pricing_type: 'fixed_price' } Charge.create(chargeData, (err, response) => { if (err) { res.status(400).send({message: err.message}); } else { res.status(200).send(response); } });});
Note: This endpoint is just to show what is possible, and not meant for in production use (e.g., you should validate incoming data).
Firstly, the chargeData variable. This object contains fields that you should retrieve from the user on the front-end. The name, description, and amount should be changed.
After that, we create the charge using the chargeData variable, and the response from this is where the interesting data lie:
- response[‘id’], the id of the charge, essential to retrieve info about payments later on. Should be saved in a database.
- response[‘hosted_url’], a link to a payment gateway hosted by Coinbase that looks like this:
I recommend printing the response, using
console.log(response)
to see more information you can print to the user. You’ll find the relevant BTC, ETH, BCH, LTC addresses if they want to make a manual payment, and more.
Now, if you create a POST request at localhost:3000/charge, you will create a charge.
Step 7: Check the status of the payment
Having created the charge, we now need to check if the user has paid. This can be done by using the id of the charge (as referred to in step (6)). This code is an example of the checks you can do:
app.post('/status', (req, res) => { let id = req.body.id Charge.retrieve(id, (err, charge) => { if(charge['timeline'][0]['status'] == 'NEW') { try { if (charge['timeline'][1]['status'] == 'PEDNING' && charge['timeline'].length == 2) { return res.status(200).send({message: 'Payment pending, awaiting confirmations.'}); } else if (charge['timeline'][1]['status'] == 'EXPIRED') { return res.status(400).send({message: 'Payment expired'}); } else if(charge['timeline'][2]['status'] == 'COMPLETED') { return res.status(200).send({message: 'Payment completed.'}); } } catch(err) { return res.status(200).send({message: 'No payment detected'}); } } else { return res.status(400).send({message: 'Charge not found.'}); } });});
A lot going on here. First of all, the id is all that’s needed to check the status.
The charge[‘timeline’] object is simply an array that gets an item pushed as something happens with the transaction.
The charge[‘timeline’] will always have a 0 element, with the status “NEW”. However, the 1st and 2nd elements don’t always exist, thus we wrap our if statement in a try-catch block.
The first element is either pending or expired. If pending, check for a 2nd element — the payment might already have been confirmed.
Step 8: Testing our routes using Postman
First of all, we’ll test creating a charge:
Our request received a 200 OK status code, meaning the charge was created. As we can see in the body we received, we have the hosted_url and the important id property.
Let’s test the /status endpoint:
The body we sent was the id found in the response to the previous request. Since no payment has been made, we received the expected message “No payment detected.”
It all seems to be working!
Final thoughts
A few thoughts before I let you get along with working on your website.
(1) This is a “bare bone” implementation. For production, add validation, csrf protection, configure headers, test sending money to your own Coinbase commerce account, etc.
(2) To avoid making this an extremely long post, I have skipped the front-end part altogether. You’ll need to implement a form on the front-end, taking the name, description, and dollar amount as parameters.
I hope it helped! If you feel it did, consider following me on Medium — they no longer pay creators with < 100 followers :(