Process Full or Partial Refunds via API

Use Case

An online marketplace, digital service, or e-commerce store wants to refund customers (fully or partially) for cancelled or disputed orders using TransactPay.


Prerequisites

  • Completed payment made through TransactPay
  • Access to the original order_id or transaction_reference
  • Your TransactPay secret key
  • Refund reason (optional but recommended)

Step-by-Step Implementation


Step 1: Prepare Refund Payload

A typical refund requires:

  • order_id or transaction_reference
  • amount (for partial refund, less than original)
  • reason (optional but useful for logging)

Node.js Example – Refund Request

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 refundPayload = {
  order_id: "TP-ORDER-001",
  amount: 5000, // NGN 5,000 refunded (partial refund)
  reason: "Customer cancelled the service"
};

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

axios
  .post("https://api.transactpay.io/payment/refund", {
    data: encrypted,
  }, {
    headers: {
      Authorization: `Bearer ${process.env.TRANSACTPAY_SECRET_KEY}`,
    },
  })
  .then((res) => {
    console.log("Refund processed:", res.data);
  })
  .catch((err) => {
    console.error("Refund 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 = {
    "order_id": "TP-ORDER-001",
    "amount": 5000,
    "reason": "Customer cancelled the service"
}

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

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

print("Refund response:", res.json())


Sample Response

{
  "status": true,
  "message": "Refund initiated successfully",
  "data": {
    "refund_id": "RF-000123",
    "status": "pending"
  }
}

Refunds may take a few hours to reflect in the customer’s account depending on the payment method.


Optional: Handle Refund Webhook

Listen for webhook events like refund.success to confirm when the refund is completed.

Example event structure:

{
  "event": "refund.success",
  "data": {
    "order_id": "TP-ORDER-001",
    "refund_id": "RF-000123",
    "amount": 5000
  }
}

Tips

  • Always log the refund reason and internal user ID
  • For full refunds, set the amount equal to original charge
  • Handle 400-level errors (e.g., "already refunded", "invalid order") gracefully