Dunning Management
Automatically handle failed recurring payments with smart retry logic.
Overview
Dunning is the process of recovering failed subscription payments. AuxVault's dunning system automatically:
- π Auto-retry - Smart retry schedule with exponential backoff
- π§ Email notifications - Alert customers of payment failures
- π Status tracking - Monitor retry attempts and success rates
- π― Recovery optimization - Maximize payment recovery
- βΈοΈ Auto-pause - Pause subscriptions after max retries
How Dunning Works
Payment Fails β Retry 1 (1 day) β Retry 2 (3 days) β Retry 3 (7 days) β Pause/Cancel
Default Retry Schedule:
- Attempt 1: 1 day after failure
- Attempt 2: 3 days after failure
- Attempt 3: 7 days after failure
- After 3 failures: Pause subscription
Get Dunning Settings
Endpoint
GET /api/v1/merchants/:merchantId/dunning-settings
curl https://dev.auxcore.net/api/v1/merchants/merchant_123/dunning-settings \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"enabled": true,
"maxRetries": 3,
"retrySchedule": [1, 3, 7],
"emailNotifications": true,
"actionAfterMaxRetries": "pause",
"gracePeriodDays": 3
}
}
Update Dunning Settings
Endpoint
PUT /api/v1/merchants/:merchantId/dunning-settings
curl -X PUT https://dev.auxcore.net/api/v1/merchants/merchant_123/dunning-settings \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"maxRetries": 4,
"retrySchedule": [1, 3, 5, 10],
"emailNotifications": true,
"actionAfterMaxRetries": "cancel"
}'
Configuration Options
Max Retries
Number of retry attempts before giving up:
{
"maxRetries": 3
}
Recommended: 3-4 retries
Retry Schedule
Days to wait between retry attempts:
{
"retrySchedule": [1, 3, 7]
}
Common schedules:
- Aggressive:
[1, 2, 3]- Quick recovery - Balanced:
[1, 3, 7]- Recommended - Patient:
[3, 7, 14]- Give customers time
Action After Max Retries
What to do when all retries fail:
| Action | Description | Use When |
|---|---|---|
pause |
Pause subscription | Default, allows reactivation |
cancel |
Cancel subscription | Permanent cancellation |
manual_review |
Flag for review | Custom handling needed |
{
"actionAfterMaxRetries": "pause"
}
Grace Period
Days to maintain access after failure:
{
"gracePeriodDays": 3
}
Customer keeps access for 3 days while retries happen.
Email Notifications
Send emails to customers:
{
"emailNotifications": true,
"emailTemplate": "payment_failed_default"
}
Monitor Failed Payments
List Failed Payments
GET /api/v1/recurring/failed-payments
curl "https://dev.auxcore.net/api/v1/recurring/failed-payments?status=retrying" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID": your-tenant-id"
Response:
{
"success": true,
"data": {
"failedPayments": [
{
"id": "fp_abc123",
"subscriptionId": "sub_456",
"customerId": "cust_789",
"amount": 99.00,
"failureReason": "Insufficient funds",
"attemptCount": 2,
"nextRetryAt": "2026-01-31T12:00:00Z",
"status": "retrying"
}
]
}
}
Manual Retry
Force an immediate retry:
Endpoint
POST /api/v1/recurring/:subscriptionId/retry-payment
curl -X POST https://dev.auxcore.net/api/v1/recurring/sub_abc123/retry-payment \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"transactionId": "txn_retry_123",
"status": "approved",
"message": "Payment successfully recovered"
}
}
Process Auto-Retry (Cron)
Trigger automatic retry processing:
Endpoint
POST /api/v1/recurring/process-auto-retry
curl -X POST https://dev.auxcore.net/api/v1/recurring/process-auto-retry \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"processed": 25,
"recovered": 18,
"stillFailing": 7,
"paused": 0
}
}
Cron Schedule
Run this endpoint on a schedule:
# Every 6 hours
0 */6 * * * curl -X POST https://dev.auxcore.net/api/v1/recurring/process-auto-retry
Webhooks
subscription.payment_failed
{
"type": "subscription.payment_failed",
"data": {
"subscriptionId": "sub_abc123",
"customerId": "cust_456",
"amount": 99.00,
"attemptCount": 1,
"declineReason": "Insufficient funds",
"nextRetryAt": "2026-01-29T12:00:00Z"
}
}
subscription.payment_recovered
{
"type": "subscription.payment_recovered",
"data": {
"subscriptionId": "sub_abc123",
"transactionId": "txn_recovered_789",
"amount": 99.00,
"attemptCount": 2,
"recoveredAt": "2026-01-30T10:00:00Z"
}
}
subscription.dunning_failed
{
"type": "subscription.dunning_failed",
"data": {
"subscriptionId": "sub_abc123",
"customerId": "cust_456",
"amount": 99.00,
"attemptCount": 3,
"action": "paused",
"lastError": "Card declined"
}
}
Email Notifications
Payment Failed Email
Automatically sent on first failure:
Subject: Payment Failed - Action Required
Content:
- Payment failure notice
- Reason for failure
- Update payment method link
- Next retry date
Final Notice Email
Sent before final retry:
Subject: Final Payment Attempt - Subscription at Risk
Content:
- Final retry warning
- Consequence (pause/cancel)
- Update payment method link
- Support contact
Payment Recovered Email
Sent when payment succeeds:
Subject: Payment Successful - Subscription Active
Content:
- Payment confirmation
- Receipt
- Next billing date
Analytics
Track dunning performance:
curl "https://dev.auxcore.net/api/v1/analytics/dunning?period=30d" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
Response:
{
"success": true,
"data": {
"totalFailures": 150,
"recovered": 120,
"stillRetrying": 20,
"paused": 10,
"recoveryRate": 0.80,
"averageRetriesForRecovery": 1.8,
"failureReasons": {
"insufficient_funds": 60,
"card_declined": 40,
"card_expired": 30,
"other": 20
}
}
}
Common Failure Reasons
| Reason | Common Cause | Customer Action |
|---|---|---|
| Insufficient funds | Not enough balance | Add funds to account |
| Card declined | Card issuer declined | Try different card |
| Card expired | Card past expiry date | Update card details |
| Invalid card | Card info incorrect | Verify card details |
| Fraud suspected | Flagged as suspicious | Contact bank |
Best Practices
β DO:
- Enable dunning - Recovers 60-80% of failed payments
- Use grace periods - Don't cut off access immediately
- Send clear emails - Help customers fix the issue
- Monitor analytics - Track recovery rates
- Optimize retry schedule - Balance recovery vs customer patience
- Update card on file - Before expiration
β DON'T:
- Don't retry too quickly - Give customers time
- Don't retry too many times - 3-4 is enough
- Don't cancel immediately - Use pause first
- Don't ignore patterns - Address common failure reasons
- Don't spam customers - Limit notification frequency
Improving Recovery Rates
1. Update Card Before Expiration
# Send email 30 days before card expires
curl -X POST /api/v1/notifications/card-expiration-reminder \
-d '{"customerId": "cust_123"}'
2. Smart Retry Timing
Retry on payday (1st and 15th of month):
{
"retrySchedule": "smart",
"preferredDays": [1, 15]
}
3. Account Updater
Automatically update expired cards:
{
"accountUpdater": true
}
4. Multiple Payment Methods
Allow backup payment methods:
{
"allowBackupCard": true
}
Testing Dunning
Trigger Failed Payment
# Use decline test card
curl -X POST https://dev.auxcore.net/api/v1/recurring/sub_test_123/process-payment \
-d '{
"card": {
"number": "4000000000000002"
}
}'
# Should fail and trigger dunning
Test Retry Logic
# Check retry schedule
curl https://dev.auxcore.net/api/v1/recurring/sub_test_123
# Manual retry
curl -X POST https://dev.auxcore.net/api/v1/recurring/sub_test_123/retry-payment
Next Steps
Need help? Contact support@auxvault.com