DEV Community

Cover image for Setting Up Recurring Charges with the Rapyd Collect API
Kyle Pollock for Rapyd

Posted on • Originally published at community.rapyd.net

Setting Up Recurring Charges with the Rapyd Collect API

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
Enter fullscreen mode Exit fullscreen mode

Then, run the following command to create a package.json file:

  npm init -y
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Open the Rapyd Client Portal in a web browser. Save access key and secret key
  2. Click Developers on the left-navigation to open the Developers page.
  3. Select Credentials Details on the Developers page.
  4. Copy the access key and secret key using the copy button.
  5. Create a new .env file in the project and paste both the values:
ACCESS_KEY=<copied-value>
SECRET_KEY=<copied-value>
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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.

Architecture diagram

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>
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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:

Application home page

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
Enter fullscreen mode Exit fullscreen mode

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.");
  }
});
Enter fullscreen mode Exit fullscreen mode

Select preferred payment method type

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>`
  );
});
Enter fullscreen mode Exit fullscreen mode

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:

Collect required payment method fields

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);
});
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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.

Complete payment flow

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.

Top comments (0)