Refunds
Create and manage refunds for payments.
Refunds API
The Refunds API allows you to refund charges that have previously been made.
The Refund Object
{
"id": "re_abc123def456",
"object": "refund",
"amount": 5000,
"currency": "GHS",
"status": "succeeded",
"payment": "pay_xyz789",
"reason": "requested_by_customer",
"failure_reason": null,
"metadata": {},
"created_at": "2024-01-15T10:00:00Z"
}Attributes
| Attribute | Type | Description |
|---|---|---|
id | string | Unique identifier |
object | string | Always "refund" |
amount | integer | Refund amount in pesewas |
currency | string | Currency code |
status | string | pending, succeeded, failed |
payment | string | Original payment ID |
reason | string | Reason for refund |
failure_reason | string | Why the refund failed |
metadata | object | Custom metadata |
created_at | string | Creation timestamp |
Create a Refund
Refunds a payment that has been made.
POST /v1/refundsRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
payment | string | Yes | Payment ID to refund |
amount | integer | No | Amount to refund (defaults to full amount) |
reason | string | No | Reason for refund |
metadata | object | No | Custom metadata |
If you don't specify an amount, the full payment amount will be refunded.
# Full refund
curl -X POST https://api.44.200.142.19.nip.io/v1/refunds \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"payment": "pay_xyz789",
"reason": "requested_by_customer"
}'
# Partial refund
curl -X POST https://api.44.200.142.19.nip.io/v1/refunds \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"payment": "pay_xyz789",
"amount": 2500,
"reason": "requested_by_customer"
}'// Full refund
const refund = await paygate.refunds.create({
payment: 'pay_xyz789',
reason: 'requested_by_customer'
})
// Partial refund
const partialRefund = await paygate.refunds.create({
payment: 'pay_xyz789',
amount: 2500, // GHS 25.00
reason: 'requested_by_customer'
})# Full refund
refund = client.refunds.create(
payment='pay_xyz789',
reason='requested_by_customer'
)
# Partial refund
partial_refund = client.refunds.create(
payment='pay_xyz789',
amount=2500,
reason='requested_by_customer'
)// Full refund
$refund = $paygate->refunds->create([
'payment' => 'pay_xyz789',
'reason' => 'requested_by_customer'
]);
// Partial refund
$partialRefund = $paygate->refunds->create([
'payment' => 'pay_xyz789',
'amount' => 2500,
'reason' => 'requested_by_customer'
]);Refund Reasons
| Reason | Description |
|---|---|
requested_by_customer | Customer requested refund |
duplicate | Duplicate payment |
fraudulent | Fraudulent transaction |
Retrieve a Refund
Retrieves a refund by ID.
GET /v1/refunds/:idcurl https://api.44.200.142.19.nip.io/v1/refunds/re_abc123def456 \
-H "Authorization: Bearer sk_test_..."const refund = await paygate.refunds.retrieve('re_abc123def456')refund = client.refunds.retrieve('re_abc123def456')List Refunds
Returns a list of refunds.
GET /v1/refundsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | Number of results (1-100) |
starting_after | string | Cursor for pagination |
payment | string | Filter by payment ID |
created[gte] | string | Filter by creation date |
created[lte] | string | Filter by creation date |
curl "https://api.44.200.142.19.nip.io/v1/refunds?payment=pay_xyz789" \
-H "Authorization: Bearer sk_test_..."const refunds = await paygate.refunds.list({
payment: 'pay_xyz789'
})refunds = client.refunds.list(payment='pay_xyz789')Refund Rules
Not all payments can be refunded. Consider these rules:
- Only succeeded payments - You can only refund payments with
status: succeeded - Refund window - Refunds must be made within 90 days of the original payment
- Partial refunds - You can refund part of a payment
- Multiple refunds - You can make multiple partial refunds until the full amount is refunded
- No reversal - Once processed, refunds cannot be canceled
Refund Statuses
| Status | Description |
|---|---|
pending | Refund is being processed |
succeeded | Refund was successful |
failed | Refund failed |
Webhook Events
| Event | Description |
|---|---|
refund.created | Refund was created |
refund.succeeded | Refund was successful |
refund.failed | Refund failed |
app.post('/webhooks', (req, res) => {
const event = Webhook.constructEvent(req.body, signature, secret)
switch (event.type) {
case 'refund.succeeded':
const refund = event.data.object
console.log(`Refund ${refund.id} succeeded`)
// Update your records
break
case 'refund.failed':
const failedRefund = event.data.object
console.log(`Refund failed: ${failedRefund.failure_reason}`)
// Handle failure
break
}
res.json({ received: true })
})Check Refundable Amount
Before creating a refund, check how much is refundable:
// Get the original payment
const payment = await paygate.payments.retrieve('pay_xyz789')
// Check refunded amount
const refunded = payment.amount_refunded || 0
const refundable = payment.amount - refunded
console.log(`Original: ${payment.amount}`)
console.log(`Refunded: ${refunded}`)
console.log(`Refundable: ${refundable}`)
if (refundable > 0) {
const refund = await paygate.refunds.create({
payment: payment.id,
amount: refundable // Full remaining amount
})
}