By Anshuman Bhardwaj
Recurring charges are a common feature in any digital service, or e-commerce applications, as they allow businesses to set up subscriptions for their customers. Recurring charges are beneficial for subscription-based services, such as streaming video or music, software-as-a-service products, such as Slack, or consumable products that need to be replenished regularly, such as monthly deliveries of coffee or other consumables. By setting up recurring charges, businesses can automate their billing process and ensure that they receive regular payments from their customers. The customers don’t have to keep a tab on the bill due dates—they can sit back, and the payment providers will notify them when a payment is due.
Rapyd is a global payment acceptance platform that supports various payment methods, such as e-wallets and international cards, bank transfers, and cash. The Rapyd Collect API has built-in support for recurring charges or subscriptions. It provides a range of features and endpoints that allow developers to quickly set up and manage recurring charges, including creating customers, linking payment methods to customers, and generating regular invoices. With the Rapyd Collect API, businesses can quickly implement recurring charges in their e-commerce applications and streamline their billing process.
In this article, you’ll create a simple application to collect recurring payments for a monthly parking subscription. To implement the application, you’ll create customer profiles, link payment methods with customers, and set up recurring charges using a Node.js server.
Implementing Recurring Charges Using the Rapyd Collect API
Before getting started, you’ll need Node version 14 or above and npm version 6 or above installed on your computer. You can also clone and set up this GitHub repository locally to follow along with the tutorial.
Setting Up the Node.js Project
Create a new project folder called rapyd-recurring-charges-example
and navigate to it in your terminal:
cd rapyd-recurring-charges-example
Then, run the following command to create a package.json
file:
npm init -y
Once the package.json
file is created, you can start installing the project dependencies. First, you need Express, a web application framework for Node.js that provides a range of features and functions for building web applications and APIs. Install Express by running the following command:
npm install express
With Express installed, you can now create a file named index.js
in your project folder and add the following code:
const express = require("express");
const app = express();
const port = 3000;
app.get("/", (request, response) => {
response.send("Rapyd example!");
});
app.listen(port, () => {
console.log(`Rapyd app listening on port ${port}`);
});
The above code creates an Express app that listens for HTTP requests on port 3000 and responds with a message when the root URL http://localhost:3000
is accessed.
To start the app, open your terminal and navigate to your project folder. Then, run the following command:
node index.js
To test the app, open your web browser and navigate to http://localhost:3000
. You should see the message “Rapyd example!” displayed in the browser.
Setting Up Request Signing
You’ll need to configure the authentication mechanism before requesting Rapyd Collect API. Rapyd verifies each request to ensure it’s coming from you and not from a malicious party.
To get started, complete the following steps:
- Open the Rapyd Client Portal in a web browser.
- Click Developers on the left-navigation to open the Developers page.
- Select Credentials Details on the Developers page.
- Copy the access key and secret key using the copy button.
- Create a new
.env
file in the project and paste both the values:
ACCESS_KEY=<copied-value>
SECRET_KEY=<copied-value>
You’ll need to restart the server using
node index.js
whenever you change any project file. You can also use Nodemon to automate this.
Now, create an utility function, makeRequest
, in the index.js
file to make signed requests to the Rapyd Collect API.
To implement this function, you’ll need to install the following npm packages:
- axios: to make HTTP requests
- crypto-js: to encrypt the request payload
- dotenv: to properly load the environment variables
Run the below command to install the above packages:
npm i axios crypto-js dotenv
Now update the index.js
file with following code to implement the makeRequest
function, as recommended by the Rapyd authentication documentation:
require("dotenv").config();
const axios = require("axios");
const CryptoJS = require("crypto-js");
const accessKey = process.env.ACCESS_KEY;
const secretKey = process.env.SECRET_KEY;
function makeRequest(path, data, method) {
const salt = CryptoJS.lib.WordArray.random(12);
const timestamp = (Math.floor(new Date().getTime() / 1000) - 10).toString();
let toSign = method + path + salt + timestamp + accessKey + secretKey;
toSign = data ? toSign + JSON.stringify(data) : toSign;
let signature = CryptoJS.enc.Hex.stringify(
CryptoJS.HmacSHA256(toSign, secretKey)
);
signature = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(signature));
const headers = {
access_key: accessKey,
signature,
salt,
timestamp,
"Content-Type": `application/json`,
};
const request = {
url: `https://sandboxapi.rapyd.net${path}`,
headers,
method,
};
if (data) {
request["data"] = data;
}
return axios(request);
}
The above code uses CryptoJS to sign the outgoing requests payload and returns the response of the axios
network request.
Solution Overview
Before starting the server implementation, it’s essential to understand the solution and go through the architecture. The below diagram explains how the user, your Node.js application, and Rapyd Collect API communicate together.
The completed process is divided into four parts, each of which is described in detail below.
Collecting Customer Information
As shown in the diagram above, the first step of the process is to collect customer information. To do this, create a new public
directory inside the project and add an HTML file, index.html
, inside it. Add the following code to create an HTML form to collect customer’s email and name:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Rapyd subscription</title>
</head>
<body>
<h1>Subscribe to monthly parking</h1>
<form action="/add-customer" method="POST">
<input required placeholder="Joe" type="text" name="name" />
<input required placeholder="joe@example.com" type="email" name="email" />
<button type="submit">Subscribe</button>
</form>
</body>
</html>
The form has three input fields (for email, name, and a submit button) and specifies an action of /add-customer
(implemented later in the next step) and a method of POST
. This means that when the form is submitted, an HTTP POST request will be sent to the /add-customer
URL with the form data included in the request body.
To serve the static HTML file from the Express app, you need to register the express.static
middleware function using the app.use
utility inside index.js
.
const express = require("express");
const app = express();
const port = 3000;
app.use(express.static("public"));
app.get("/", (request, response) => {
response.send("Rapyd example!");
});
app.listen(port, () => {
console.log(`Rapyd app listening on port ${port}`);
});
Now when a request is made for a http://localhost:3000
, the public/index.html
file will be served to the client without any further processing by the app, as shown in the image below:
Selecting Preferred Payment Method
To accept and parse the form data from the incoming requests, you’ll need to configure the express.json()
and express.urlencoded()
middlewares in your index.js
file, as shown in the code below:
// ... other imports
app.use(express.static("public"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get("/", (request, response) => {
response.send("Rapyd example!");
});
// ... rest of the code
For this first step, you need to collect the user’s information and prompt them to select their preferred payment method. To do this, create a POST request handler for the /add-customer
endpoint.
This endpoint accepts the form submission data from index.html
and responds with the available payment methods for USD in India using the /v1/payment_methods/countries
API from Rapyd. The response contains another HTML form with a select
input element that submits to the /add-payment-method
endpoint.
app.post("/add-customer", async (request, response) => {
const paymentMethodsEndpoint =
"/v1/payment_methods/countries/IN?currency=USD";
try {
const { email, name } = request.body;
const methods = await makeRequest(paymentMethodsEndpoint, null, "get");
response.send(
`
<h1>Select payment method</h1>
<form action="/add-payment-method?email=${email}&name=${name}" method="post">
<select name="method_type">
${methods.data.data.map(
(item) =>
`<option value="${item.type}" name="${item.name}">${item.name}</option>`
)}
</select>
<button type="submit">Proceed</button>
</form>`
);
} catch (e) {
response.send("Something went wrong.");
}
});
Collecting Preferred Payment Method Information
As the second step, you need to collect the selected payment method information. For this purpose, implement a POST request handler for the /add-payment-method
endpoint to handle the form submission from the previous step.
app.post("/add-payment-method", async (request, response) => {
const { method_type } = request.body;
const { email, name } = request.query;
const methodRequiredFields = await makeRequest(
`/v1/payment_methods/required_fields/${method_type}`,
null,
"get"
);
response.send(
`
<h1>Payment method information</h1>
<form action="/subscribe?email=${email}&name=${name}&method_type=${method_type}" method="post">
${methodRequiredFields.data.data.fields
.map(
(item) =>
`<input placeholder="${item.instructions}" name="${item.name}"/>`
)
.join("<br />")}
<br />
<button type="submit">Proceed</button>
</form>`
);
});
The above handler accepts the user’s selected payment method type and responds with another form to request the required information fields for the selected payment method. This form will submit a POST request to the /subscribe
endpoint with the payment method required fields. The resulting form is shown below:
Creating the Customer Profile
To handle the form submission request from the previous step, create a new /subscribe
endpoint. This handler receives the email
, name
, and method_type
as the incoming request’s query params and the required payment fields as the incoming request’s body.
Now that you have collected all the required information to create a new customer profile, you can finally make a request to Rapyd’s /v1/customers
API endpoint to create a customer profile. You’ll receive the newly created customer object as the response.
app.post("/subscribe", async (request, response) => {
const { email, name, method_type } = request.query;
const customerData = {
email,
name,
payment_method: {
fields: request.body,
type: method_type,
complete_payment_url: "https://complete.rapyd.net",
error_payment_url: "https://error.rapyd.net",
},
};
const createCustomerPath = "/v1/customers";
const answer = await makeRequest(createCustomerPath, customerData, "post");
const customerProfile = answer.data.data;
const customerId = customerProfile.id;
response.send(customerId);
});
Creating Subscription and Collecting Payment
As the final step, you need to create a monthly payment subscription to receive recurring payment from the newly created customer.
To create a subscription, you’ll need the subscription_items
information, such as the plan
ID. If you don’t already have a subscription plan, you can create a new product and plan by following this documentation.
You also need to provide the payment_method
in the subscription request so that the checkout page preloads with the customer’s preferred payment method. You must specify the customer’s country while creating the subscription to ensure that their default payment method is selected on the checkout page.
Use the complete_payment_url
and error_payment_url
fields to specify where to redirect the user after payment is successfully completed or failed.
Once the subscription is created, you must redirect the user to the redirect_url
to take them to the hosted subscription checkout page, where they can complete the payment.
app.post("/subscribe", async (request, response) => {
const { email, name, method_type } = request.query;
const customerData = {
email,
name,
payment_method: {
fields: request.body,
type: method_type,
complete_payment_url: "https://complete.rapyd.net",
error_payment_url: "https://error.rapyd.net",
},
};
const createCustomerPath = "/v1/customers";
const answer = await makeRequest(createCustomerPath, customerData, "post");
const customerProfile = answer.data.data;
const customerId = customerProfile.id;
const subscriptionPayload = {
customer: customerId,
country: "in",
billing: "pay_automatically",
payment_method: customerProfile.default_payment_method,
subscription_items: [
{
plan: "plan_af8a418da8f6d5b08af5d68e7021105d",
quantity: 1,
},
],
};
const checkoutPath = "/v1/checkout/subscription";
const subsAnswer = await makeRequest(
checkoutPath,
subscriptionPayload,
"post"
);
const subscriptionData = subsAnswer.data.data;
response.redirect(subscriptionData.redirect_url);
});
An invoice is generated automatically for the subscription, which you can view on the Rapyd Client Portal, as explained in viewing subscription invoices.
Your monthly parking subscription application is ready.
Conclusion
You’ve successfully created an application to collect monthly parking subscription payments. While doing so, you learned about different Rapyd Collect API endpoints, such as the API to manage customer profiles, payment methods, and hosted checkout page for recurring payments. You also learned about authenticating and protecting your application server when working with payment platforms like Rapyd.
Rapyd is a fintech platform that provides a range of tools and services, including payments, payouts, fraud protection, compliance support, and business support to help businesses succeed in the digital economy. Whether you’re a small business just starting out or a large enterprise looking to expand your global reach, Rapyd can help you thrive in today’s digital economy.