PRA Refund Decline Queue
Automatically manage and retry declined refunds (Payment Refund Authorization).
Overview
The Refund Decline Queue handles offline refund declines with automatic retry logic. When a refund is declined, it:
- 📥 Automatically queued - No manual intervention needed
- 🔄 Smart retry - Exponential backoff (5min → 24hr)
- 📊 Full tracking - Complete audit trail
- ✅ Auto-resolution - Marks resolved when successful
- 🔔 Notifications - Alerts when action needed
- 🛠️ Manual control - Retry, resolve, or cancel anytime
How It Works
1. Refund Attempted → 2. Declined → 3. Added to Queue
↓
4. Resolved ← 3. Auto-Retry (every 5min-24hr) ← Manual Retry
List Queue Entries
Endpoint
GET /api/v1/refund-decline-queue
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status |
merchantId |
string | Filter by merchant |
fromDate |
date | Start date |
toDate |
date | End date |
page |
integer | Page number |
limit |
integer | Items per page |
curl "https://dev.auxcore.net/api/v1/refund-decline-queue?status=pending" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"entries": [
{
"id": "rdq_abc123",
"transactionId": "txn_original_456",
"refundTransactionId": "ref_declined_789",
"amount": 150.75,
"currency": "USD",
"status": "pending",
"declineReason": "Account closed",
"declineCode": "R02",
"gatewayType": "NMI",
"attemptCount": 1,
"maxAttempts": 3,
"lastAttemptAt": "2026-01-28T15:00:00Z",
"scheduledRetryAt": "2026-01-28T15:05:00Z",
"createdAt": "2026-01-28T15:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 15,
"pages": 1
}
}
}
Queue Entry Statuses
| Status | Description |
|---|---|
pending |
Waiting for next retry attempt |
processing |
Currently being processed |
retry |
In retry queue |
resolved |
Successfully refunded |
failed |
Max attempts reached, failed |
cancelled |
Manually cancelled |
Get Queue Entry
Endpoint
GET /api/v1/refund-decline-queue/:entryId
curl https://dev.auxcore.net/api/v1/refund-decline-queue/rdq_abc123 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"id": "rdq_abc123",
"transactionId": "txn_original_456",
"refundTransactionId": "ref_declined_789",
"amount": 150.75,
"currency": "USD",
"status": "retry",
"declineReason": "Account closed",
"declineCode": "R02",
"gatewayType": "NMI",
"gatewayResponse": {
"code": "R02",
"message": "Account closed"
},
"attemptCount": 2,
"maxAttempts": 3,
"lastAttemptAt": "2026-01-28T15:10:00Z",
"scheduledRetryAt": "2026-01-28T15:20:00Z",
"attempts": [
{
"attemptNumber": 1,
"attemptedAt": "2026-01-28T15:00:00Z",
"result": "declined",
"error": "Account closed"
},
{
"attemptNumber": 2,
"attemptedAt": "2026-01-28T15:10:00Z",
"result": "declined",
"error": "Account closed"
}
],
"createdAt": "2026-01-28T15:00:00Z",
"updatedAt": "2026-01-28T15:10:00Z"
}
}
Manual Retry
Manually trigger a retry attempt.
Endpoint
POST /api/v1/refund-decline-queue/:entryId/retry
curl -X POST https://dev.auxcore.net/api/v1/refund-decline-queue/rdq_abc123/retry \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"id": "rdq_abc123",
"status": "processing",
"message": "Retry initiated",
"scheduledRetryAt": "2026-01-28T15:15:00Z"
}
}
⚠️ Note: Manual retries reset the attempt counter.
Manual Resolution
Mark an entry as resolved (e.g., refunded through different method).
Endpoint
POST /api/v1/refund-decline-queue/:entryId/resolve
curl -X POST https://dev.auxcore.net/api/v1/refund-decline-queue/rdq_abc123/resolve \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"notes": "Refunded via check",
"refundMethod": "check",
"refundDate": "2026-01-28"
}'
Response:
{
"success": true,
"data": {
"id": "rdq_abc123",
"status": "resolved",
"resolvedAt": "2026-01-28T15:30:00Z",
"resolvedBy": "user_123",
"resolutionNotes": "Refunded via check"
}
}
Cancel Entry
Cancel a queue entry (e.g., customer no longer wants refund).
Endpoint
POST /api/v1/refund-decline-queue/:entryId/cancel
curl -X POST https://dev.auxcore.net/api/v1/refund-decline-queue/rdq_abc123/cancel \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-d '{
"reason": "Customer request",
"notes": "Customer called to cancel refund"
}'
Response:
{
"success": true,
"data": {
"id": "rdq_abc123",
"status": "cancelled",
"cancelledAt": "2026-01-28T15:40:00Z",
"cancelledBy": "user_123",
"cancellationReason": "Customer request"
}
}
Automatic Retry Schedule
The system automatically retries declined refunds with exponential backoff:
| Attempt | Delay | Cumulative Time |
|---|---|---|
| 1 | Immediate | 0 min |
| 2 | 5 minutes | 5 min |
| 3 | 10 minutes | 15 min |
| 4 | 20 minutes | 35 min |
| 5 | 1 hour | 1h 35min |
| 6 | 2 hours | 3h 35min |
| 7 | 6 hours | 9h 35min |
| 8 | 12 hours | 21h 35min |
| 9 | 24 hours | 45h 35min |
After max attempts (default 3), status becomes failed.
Process Retries (Cron Endpoint)
Trigger automatic retry processing (call this from a cron job).
Endpoint
POST /api/v1/refund-decline-queue/process-retries
curl -X POST https://dev.auxcore.net/api/v1/refund-decline-queue/process-retries \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"processed": 5,
"resolved": 2,
"requeued": 3,
"failed": 0
}
}
Cron Schedule
Recommended cron schedule (every 5 minutes):
*/5 * * * * curl -X POST https://dev.auxcore.net/api/v1/refund-decline-queue/process-retries \
-H "X-Tenant-ID: your-tenant-id" \
-H "x-internal-service-key: YOUR_KEY"
Common Decline Reasons
| Code | Reason | Recommended Action |
|---|---|---|
| R02 | Account closed | Contact customer for new account |
| R03 | No account found | Verify account details |
| R04 | Invalid account | Check routing/account numbers |
| R10 | Not authorized | Customer needs to authorize |
| R29 | Corporate action | Contact customer's bank |
Webhooks
refund_decline_queue.created
{
"type": "refund_decline_queue.created",
"data": {
"id": "rdq_abc123",
"transactionId": "txn_456",
"amount": 150.75,
"declineReason": "Account closed"
}
}
refund_decline_queue.resolved
{
"type": "refund_decline_queue.resolved",
"data": {
"id": "rdq_abc123",
"transactionId": "txn_456",
"amount": 150.75,
"resolvedAt": "2026-01-28T16:00:00Z"
}
}
refund_decline_queue.failed
{
"type": "refund_decline_queue.failed",
"data": {
"id": "rdq_abc123",
"transactionId": "txn_456",
"amount": 150.75,
"attemptCount": 3,
"lastError": "Account closed"
}
}
Analytics
Track queue performance:
curl "https://dev.auxcore.net/api/v1/refund-decline-queue/stats?period=30d" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"totalEntries": 150,
"resolved": 120,
"failed": 10,
"pending": 20,
"resolutionRate": 0.80,
"averageAttempts": 2.3,
"averageResolutionTime": "4h 30m"
}
}
Best Practices
✅ DO:
- Monitor the queue daily - Check for failed entries
- Set up webhooks - Get notified of failures
- Review failed entries - Contact customers if needed
- Document resolutions - Add notes when resolving manually
- Run cron regularly - Every 5 minutes recommended
- Track resolution rates - Identify patterns
❌ DON'T:
- Don't ignore failed entries - Follow up with customers
- Don't retry excessively - 3-5 attempts is sufficient
- Don't cancel prematurely - Give system time to resolve
- Don't skip notes - Always document manual actions
- Don't forget notifications - Alert customers of status
Troubleshooting
High Failure Rate
If seeing many failures:
- Check decline reasons
- Contact gateway support
- Review customer account statuses
- Consider alternative refund methods
Queue Not Processing
If retries aren't happening:
- Verify cron is running
- Check server logs
- Test
/process-retriesendpoint - Ensure service is healthy
Stuck Entries
If entries stuck in processing:
- Check for service errors
- Manually retry
- Contact support if persists
Next Steps
Need help? Contact support@auxvault.com