Implement Recurring Payments Using Saved Cards

๐Ÿ“˜ Use Case

A gym, SaaS app, or digital magazine wants to automatically charge users on a recurring schedule using saved card details without requiring them to re-enter payment info each month.


Why Use Tokenization?

  • Enhances UX: No need for repeat card input
  • PCI-compliant method for storing payment credentials
  • Enables auto-renewals, subscriptions, and payment retries

Prerequisites

  • TransactPay merchant account with tokenization enabled
  • Backend (Node.js or Python)
  • Initial one-time card transaction to collect token
  • Customer consent for recurring charges

Step-by-Step Guide


Step 1: Collect Card Payment and Store Token

During the initial payment, ensure the payload allows for tokenization:

{
  "amount": 10000,
  "currency": "NGN",
  "redirect_url": "https://yourapp.com/success",
  "customer_email": "[email protected]",
  "save_card": true
}

In your backend, encrypt this payload and call the order creation endpoint as shown in Tutorial 4.

Once payment is completed, the response or webhook will include a payment token, e.g.:

{
  "status": true,
  "data": {
    "token": "tok_abc123xyz"
  }
}

Save the token securely with the associated customer ID.


Step 2: Schedule Recurring Charges

Whenever it's time to charge the customer (e.g., monthly), you can use the saved token.


Node.js Example โ€“ Charge Saved Token

const axios = require("axios");
const NodeRSA = require("node-rsa");
const fs = require("fs");
require("dotenv").config();

const pubKey = fs.readFileSync("./transactpay_pub.pem", "utf8");
const rsa = new NodeRSA(pubKey);
rsa.setOptions({ encryptionScheme: "pkcs1" });

const recurringPayload = {
  token: "tok_abc123xyz", // token from previous payment
  amount: 10000,
  currency: "NGN",
  reference: "SUB-2025-001",
  customer_email: "[email protected]"
};

const encrypted = rsa.encrypt(JSON.stringify(recurringPayload), "base64");

axios
  .post("https://api.transactpay.io/payment/charge/token", {
    data: encrypted,
  }, {
    headers: {
      Authorization: `Bearer ${process.env.TRANSACTPAY_SECRET_KEY}`,
    },
  })
  .then((res) => {
    console.log("Recurring charge:", res.data);
  })
  .catch((err) => {
    console.error("Recurring payment error:", err.response?.data || err.message);
  });
import json, requests, os
from dotenv import load_dotenv
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding

load_dotenv()
key = os.getenv("TRANSACTPAY_SECRET_KEY")

with open("transactpay_pub.pem", "rb") as key_file:
    pub_key = serialization.load_pem_public_key(key_file.read())

payload = {
    "token": "tok_abc123xyz",
    "amount": 10000,
    "currency": "NGN",
    "reference": "SUB-2025-001",
    "customer_email": "[email protected]"
}

encrypted = pub_key.encrypt(json.dumps(payload).encode(), padding.PKCS1v15())

res = requests.post(
    "https://api.transactpay.io/payment/charge/token",
    headers={"Authorization": f"Bearer {key}"},
    json={"data": encrypted.hex()}
)

print("Response:", res.json())

Scheduling Tips

  • Use cron jobs or background workers to automate billing
  • Implement retry logic for failed charges
  • Send email reminders before and after billing

Example Response

{
  "status": true,
  "message": "Charge successful",
  "data": {
    "reference": "SUB-2025-001",
    "amount": 10000,
    "status": "success"
  }
}

Best Practices

  • Always get customer consent before recurring charges
  • Handle payment failures gracefully
  • Update tokens if card expires (TransactPay may notify you)