Refund

EnvironmentBase URL
Sandboxhttps://beta-collect.paga.com
Livehttps://collect.paga.com

Works with payment requests made through Dynamic virtual account, Bank USSD and Paga Wallet. Authenticate as in Authentication.

What you can do

Persistent Payment Identifiers. Refunds on Persistent Payment Identifiers only work for payments made by NIP bank transfer.

How it works

Send a refund

POST /refund/v2
Authorization: Basic base64(publicKey:secretKey)
hash: sha512(referenceNumber + refundAmount + hashKey)
Content-Type: application/json
{
  "referenceNumber": "RFD-2026-0031",
  "paymentRequestReference": "ORD-2026-0187",
  "refundAmount": 1000.0,
  "currency": "NGN",
  "reason": "Item out of stock"
}
{
  "referenceNumber": "RFD-2026-0031",
  "statusCode": "0",
  "statusMessage": "success",
  "refundAmount": 1000.0,
  "currency": "NGN",
  "refundDestination": "Paga | 00012346433"
}
All request parameters (5)
ParameterRequiredDescription
referenceNumberYesA new, unique reference for this refund. Sending the same one again won’t refund twice. Hash value 1
paymentRequestReferenceYesThe referenceNumber of the payment request you’re refunding
refundAmountYesAmount to return. Use the full amount for a full refund. Hash value 2
currencyYesNGN
reasonNoWhy you’re refunding. Helps your team and Paga support trace it later
Response fields (6)
FieldMeaning
referenceNumberYour refund reference
statusCode0 means the refund was accepted
statusMessageReadable status
refundAmountAmount refunded
currencyCurrency of the refund
refundDestinationWhere the money went, as bank or Paga, then the account number

Partial refunds

Send one refund request per partial refund, each with its own reference. For example, for a ₦10,000 payment:

Refund referenceRefundedLeft to refund
RFD-2026-0031₦3,000₦7,000
RFD-2026-0032₦2,000₦5,000
RFD-2026-0033₦5,000₦0

All three use the same paymentRequestReference: ORD-2026-0187.

Cancel an unpaid request

Use the same endpoint on a request that hasn’t been paid. Paga closes the request, and your customer can no longer pay it. Your callback URL receives a final callback.

Check refund status

Call POST /status with the original payment request reference. Its data.refundStatus shows whether it has been refunded.

{
  "referenceNumber": "ORD-2026-0187"
}
{
  "statusCode": "0",
  "data": {
    "referenceNumber": "ORD-2026-0187",
    "totalPaymentAmount": 10000.0,
    "refundStatus": "refunded"
  }
}

Good to know