List Transfer Reversals
Overview
Retrieve all Reversals (refunds) for a specific Transfer. Track refund history, calculate total refunded, and verify refund status.
Resource Access
- User Permissions: Admin users only
- Endpoint:
GET /transfers/\{transfer_id}/reversals
Arguments
| Parameter | Type | Required | Description |
|---|---|---|---|
| transfer_id | string | Yes | ID of original Transfer (in URL path) |
Example Request
curl -X GET \
'https://api.ahrvo.network/payments/na/transfers/TRtransfer789/reversals' \
-u username:password
Example Response (Multiple Reversals)
{
"_embedded": {
"transfers": [
{
"id": "TRreversal123",
"created_at": "2023-12-11T15:30:00Z",
"updated_at": "2023-12-11T15:30:10Z",
"amount": 3000,
"currency": "USD",
"state": "SUCCEEDED",
"type": "REVERSAL",
"merchant": "MUmerchant123",
"source": null,
"destination": "PIcreditCard456",
"fee": 0,
"ready_to_settle_at": "2023-12-11T15:30:10Z",
"trace_id": "TRC_98765435",
"parent_transfer": "TRtransfer789",
"tags": {
"reason": "partial_return",
"items_returned": "1",
"refund_type": "partial"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRreversal123"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer789"
}
}
},
{
"id": "TRreversal124",
"created_at": "2023-12-12T10:15:00Z",
"updated_at": "2023-12-12T10:15:08Z",
"amount": 2000,
"currency": "USD",
"state": "SUCCEEDED",
"type": "REVERSAL",
"merchant": "MUmerchant123",
"source": null,
"destination": "PIcreditCard456",
"fee": 0,
"ready_to_settle_at": "2023-12-12T10:15:08Z",
"trace_id": "TRC_98765436",
"parent_transfer": "TRtransfer789",
"tags": {
"reason": "partial_return",
"items_returned": "1",
"refund_type": "partial"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRreversal124"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer789"
}
}
}
]
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer789/reversals"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer789"
}
},
"page": {
"limit": 20,
"offset": 0,
"count": 2
}
}
Example Response (No Reversals)
{
"_embedded": {
"transfers": []
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer790/reversals"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer790"
}
},
"page": {
"limit": 20,
"offset": 0,
"count": 0
}
}
Example Response (Pending Reversal)
{
"_embedded": {
"transfers": [
{
"id": "TRreversal125",
"created_at": "2023-12-13T14:00:00Z",
"updated_at": "2023-12-13T14:00:00Z",
"amount": 10000,
"currency": "USD",
"state": "PENDING",
"type": "REVERSAL",
"merchant": "MUmerchant123",
"source": null,
"destination": "PIcreditCard456",
"fee": 0,
"ready_to_settle_at": null,
"trace_id": "TRC_98765437",
"parent_transfer": "TRtransfer791",
"tags": {
"reason": "customer_request",
"refund_type": "full"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRreversal125"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer791"
}
}
}
]
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer791/reversals"
},
"parent": {
"href": "https://api.ahrvo.network/payments/na/transfers/TRtransfer791"
}
},
"page": {
"limit": 20,
"offset": 0,
"count": 1
}
}
Additional Information
- Reversals are Transfers: Each reversal is a full Transfer object
- Has own Transfer ID (starts with "TR")
- Type = "REVERSAL"
- Can be fetched individually via GET /transfers/{reversal_id}
- Appears in GET /transfers list
- Has all standard Transfer fields
- Parent Transfer: Links back to original
parent_transferfield contains original Transfer ID- Same for all reversals of one transfer
- Use to group refunds
- Multiple Reversals: Possible
- Can refund same transfer multiple times
- Each appears in list
- Sum amounts to see total refunded
- Example: $100 charge → $30 refund + $20 refund = $50 total
- States: Check reversal status
- PENDING: Refund submitted, processing
- Just created
- Awaiting processor
- Should succeed within minutes to hours
- SUCCEEDED: Refund processed
- Funds returned to customer
- Will appear in customer's account in 5-10 days
- Ready to settle (deducted from merchant)
- FAILED: Refund failed (rare)
- Card closed, expired, etc.
- Check messages for details
- May need alternative refund method
- PENDING: Refund submitted, processing
- Amount: Refund amount
- In cents
- May be partial refund
- Sum all reversals to get total refunded
- Cannot exceed original transfer amount
- Fee: Always 0 for reversals
- No processing fee on refunds
- Original transfer fee NOT returned
- Merchant loses original fee
- Destination: Customer's payment instrument
- Same as original
source - Where refund goes
- Customer's card or bank account
- Same as original
- Source: Null for reversals
- Not charging anyone
- Funds come from merchant
- Opposite of original transfer
- Empty List: No refunds
_embedded.transfersis empty arraypage.countis 0- Transfer never refunded
- Normal for most transactions
- Chronological Order: Newest first
- Most recent reversal at top
- Ordered by creation date
- Cannot change sort order
- No Pagination: Typically few reversals
- Most transfers have 0-1 reversals
- Rare to have many
- Full list returned
- No need for cursors
Use Cases
Calculate Total Refunded
// Get all reversals
const response = await listReversals('TRtransfer789');
const reversals = response._embedded.transfers;
// Sum successful refunds only
const totalRefunded = reversals
.filter(r => r.state === 'SUCCEEDED')
.reduce((sum, r) => sum + r.amount, 0);
// Get original transfer
const transfer = await fetchTransfer('TRtransfer789');
// Calculate remaining
const remainingRefundable = transfer.amount - totalRefunded;
console.log(`Original amount: $${transfer.amount / 100}`);
console.log(`Total refunded: $${totalRefunded / 100}`);
console.log(`Remaining refundable: $${remainingRefundable / 100}`);
Check Refund Status
// Customer: "Where's my refund?"
const response = await listReversals('TRtransfer789');
const reversals = response._embedded.transfers;
if (reversals.length === 0) {
console.log('No refund has been issued');
} else {
reversals.forEach(reversal => {
console.log(`Refund ID: ${reversal.id}`);
console.log(`Amount: $${reversal.amount / 100}`);
console.log(`Status: ${reversal.state}`);
console.log(`Created: ${reversal.created_at}`);
if (reversal.state === 'SUCCEEDED') {
console.log('Refund processed. Will appear in 5-10 business days.');
} else if (reversal.state === 'PENDING') {
console.log('Refund is processing. Please check back later.');
} else if (reversal.state === 'FAILED') {
console.log('Refund failed. Please contact support.');
}
});
}
Refund History Report
# Get all reversals for a transfer
curl -X GET \
'https://api.ahrvo.network/payments/na/transfers/TRtransfer789/reversals' \
-u username:password
# Display refund history
# Date | Amount | Reason | Status
# 2023-12-11 | $30 | partial_return | SUCCEEDED
# 2023-12-12 | $20 | partial_return | SUCCEEDED
# Total refunded: $50 of $100
Prevent Over-Refunding
// Before creating new refund, check existing
async function canRefund(transferId, requestedAmount) {
const transfer = await fetchTransfer(transferId);
const reversalsResponse = await listReversals(transferId);
const reversals = reversalsResponse._embedded.transfers;
// Calculate total already refunded (including pending)
const totalRefunded = reversals
.filter(r => r.state !== 'FAILED')
.reduce((sum, r) => sum + r.amount, 0);
// Check if new refund would exceed original
const totalAfterRefund = totalRefunded + requestedAmount;
if (totalAfterRefund > transfer.amount) {
throw new Error(
`Cannot refund $${requestedAmount / 100}. ` +
`Already refunded $${totalRefunded / 100} of $${transfer.amount / 100}.`
);
}
return true;
}
// Usage
await canRefund('TRtransfer789', 3000);
await createReversal('TRtransfer789', { refund_amount: 3000 });
Track Partial Refunds
// Display partial refund breakdown
const response = await listReversals('TRtransfer789');
const reversals = response._embedded.transfers;
const transfer = await fetchTransfer('TRtransfer789');
console.log(`Original Order: $${transfer.amount / 100}`);
console.log('Refund History:');
reversals.forEach((reversal, index) => {
const reason = reversal.tags?.reason || 'Unknown';
const items = reversal.tags?.items_returned || 'N/A';
console.log(
` ${index + 1}. $${reversal.amount / 100} - ${reason} ` +
`(${items} items) - ${reversal.state}`
);
});
const totalRefunded = reversals
.filter(r => r.state === 'SUCCEEDED')
.reduce((sum, r) => sum + r.amount, 0);
console.log(`Total Refunded: $${totalRefunded / 100}`);
console.log(`Net Sale: $${(transfer.amount - totalRefunded) / 100}`);
Best Practices
- Check Before Creating: Always check existing reversals
- Prevent over-refunding
- Show customer refund history
- Calculate remaining refundable amount
- Display in admin UI
- Include PENDING: When calculating totals
- PENDING reversals count toward total
- Will become SUCCEEDED soon
- Prevents duplicate refunds
- Only exclude FAILED
- Store Reversal IDs: Track in your database
- Link to orders
- Customer service reference
- Accounting reconciliation
- Audit trail
- Customer Communication: Use for status updates
- List all refunds issued
- Show amounts and dates
- Display current status
- Set expectations (5-10 days)
- Error Handling: Handle empty lists
- Check
page.countorlength - Display "No refunds" message
- Don't assume refunds exist
- Graceful UI
- Check
- Tags: Analyze refund reasons
- Track why refunds issued
reasontag patterns- Product quality issues
- Customer satisfaction metrics
- Improve processes
Common Workflows
Customer Refund Status Check
- Customer provides order number
- Look up order, get transfer ID
- List reversals for transfer
- If empty: "No refund issued"
- If exists: Show status and timeline
- If PENDING: "Processing, 5-10 days"
- If SUCCEEDED: "Processed, may take 5-10 days to appear"
Accounting Reconciliation
- Get all transfers for period
- For each transfer:
- List reversals
- Calculate net amount (original - refunds)
- Sum net amounts
- Compare to settlement totals
- Investigate discrepancies
Customer Service Dashboard
// Display order with refund info
async function getOrderSummary(orderId) {
// Get transfer from order
const transfer = await fetchTransferByOrder(orderId);
// Get all refunds
const reversalsResponse = await listReversals(transfer.id);
const reversals = reversalsResponse._embedded.transfers;
// Calculate totals
const totalRefunded = reversals
.filter(r => r.state === 'SUCCEEDED')
.reduce((sum, r) => sum + r.amount, 0);
const pendingRefunds = reversals
.filter(r => r.state === 'PENDING')
.reduce((sum, r) => sum + r.amount, 0);
return {
orderId,
chargeAmount: transfer.amount,
totalRefunded,
pendingRefunds,
netAmount: transfer.amount - totalRefunded - pendingRefunds,
refundHistory: reversals.map(r => ({
id: r.id,
amount: r.amount,
state: r.state,
date: r.created_at,
reason: r.tags?.reason
}))
};
}
Refund Analytics
// Analyze refund patterns
async function analyzeRefunds(merchantId, startDate, endDate) {
// Get all transfers in period
const transfers = await listTransfers({
merchant: merchantId,
'created_at.gte': startDate,
'created_at.lte': endDate,
state: 'SUCCEEDED'
});
let totalCharges = 0;
let totalRefunds = 0;
const refundReasons = {};
for (const transfer of transfers) {
totalCharges += transfer.amount;
// Get reversals for each transfer
const reversalsResponse = await listReversals(transfer.id);
const reversals = reversalsResponse._embedded.transfers;
reversals.forEach(reversal => {
if (reversal.state === 'SUCCEEDED') {
totalRefunds += reversal.amount;
const reason = reversal.tags?.reason || 'Unknown';
refundReasons[reason] = (refundReasons[reason] || 0) + 1;
}
});
}
return {
totalCharges: totalCharges / 100,
totalRefunds: totalRefunds / 100,
refundRate: (totalRefunds / totalCharges * 100).toFixed(2) + '%',
refundReasons
};
}
Related Endpoints
- POST /transfers: Create original transfer
- POST /transfers/{id}/reversals: Create new refund
- GET /transfers: List all transfers (including reversals)
- GET /transfers/{id}: Fetch transfer/reversal details
- PUT /transfers/{id}: Update transfer/reversal tags