Refunds
Cancel a payment request before it’s paid, or refund a completed payment in full or in several parts. The money goes back to the account it came from.
| Environment | Base URL |
|---|---|
| Sandbox | https://beta-collect.paga.com |
| Live | https://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
Cancel a request
Stop an unpaid request so your customer can no longer pay it, for example when an order is cancelled.
Full refund
Return the whole amount to your customer.
Partial refunds
Return part of the amount, and send more refunds later, for example when only some items are returned.
Persistent Payment Identifiers. Refunds on Persistent Payment Identifiers only work for payments made by NIP bank transfer.
How it works
Create a refund reference
Give every refund its own referenceNumber. It stops the same refund being processed twice.
Send the refund
Include the original payment request’s reference in paymentRequestReference and the amount to return.
Paga returns the money
The response tells you where it went, in refundDestination.
Confirm the refund
Check status with the original payment request reference.
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"
}Request parameters (5)
| Parameter | Required | Description |
|---|---|---|
referenceNumber | Yes | A new, unique reference for this refund. Sending the same one again won’t refund twice. Hash value 1 |
paymentRequestReference | Yes | The referenceNumber of the payment request you’re refunding |
refundAmount | Yes | Amount to return. Use the full amount for a full refund. Hash value 2 |
currency | Yes | NGN |
reason | No | Why you’re refunding. Helps your team and Paga support trace it later |
{
"referenceNumber": "RFD-2026-0031",
"statusCode": "0",
"statusMessage": "success",
"refundAmount": 1000.0,
"currency": "NGN",
"refundDestination": "Paga | 00012346433"
}Response fields (6)
| Field | Meaning |
|---|---|
referenceNumber | Your refund reference |
statusCode | 0 means the refund was accepted |
statusMessage | Readable status |
refundAmount | Amount refunded |
currency | Currency of the refund |
refundDestination | Where 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 reference | Refunded | Left 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 the status endpoint with the original payment request’s reference, not the refund reference.
POST /status
Authorization: Basic base64(publicKey:secretKey)
hash: sha512(referenceNumber + hashKey)
Content-Type: application/json{
"referenceNumber": "ORD-2026-0187"
}Request parameters (1)
| Parameter | Required | Description |
|---|---|---|
referenceNumber | Yes | The referenceNumber of the original payment request. Hash value 1 |
{
"referenceNumber": "ORD-2026-0187",
"statusCode": "0",
"statusMessage": "success",
"data": {
"referenceNumber": "ORD-2026-0187",
"statusCode": "0",
"statusMessage": "success",
"requestAmount": 10000.0,
"totalPaymentAmount": 10000.0,
"expiryDateTimeUTC": "2026-11-10T15:35:00",
"additionalData": {},
"refundStatus": "refunded"
}
}Response fields (11)
| Field | Meaning |
|---|---|
referenceNumber | The payment request you asked about |
statusCode | 0 means your status request worked |
statusMessage | Readable status of your status request |
data.referenceNumber | The payment request you asked about |
data.statusCode | The payment’s own status. See Collect API status codes |
data.statusMessage | Readable status of the payment |
data.requestAmount | The amount you asked for |
data.totalPaymentAmount | The amount your customer paid |
data.expiryDateTimeUTC | When the payment request expired, in UTC |
data.additionalData | Extra details for some payment methods. Often empty |
data.refundStatus | The refund’s status, such as refunded. Only present once a refund has been made |
Good to know
Use version 2
/refund/v2 supports partial and repeat refunds. The older /refund takes only the payment request reference and isn’t recommended for new integrations.
Retry safely
If a refund times out, send it again with the same referenceNumber. Paga won’t refund twice.
Keep a refund ledger
Store each refund reference and amount against the original order, so you always know what’s left to refund.
Test in Sandbox first
Make a test payment with the bank transfer simulator, then refund it.
Need help? We’re here 24/7
Talk to our support team any time, or ask questions in the developer community.
Updated about 21 hours ago

