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)
Updated 1 day ago