Dunning Management#
How AuxCORE handles failed recurring payments: automatic retries, customer notices, and recovery tools.
Overview#
When a scheduled charge is declined, AuxCORE automatically:
- 🔄 Auto-retries - Retries the charge on a fixed schedule
- 📧 Notifies the customer - Payment-failed email after each failed run, a dunning notice when retries run out
- ⏸️ Auto-pauses - Subscriptions are paused after the last retry; payment plans become
defaulted - 📊 Tracks attempts - Failure counters and an activity log on every schedule
All endpoints on this page use admin authentication (Authorization: Bearer YOUR_JWT + X-Tenant-ID). See Subscriptions.
How Dunning Works#
Subscriptions (recurring schedules)#
Payment fails → retry after 24h → retry after 24h → ... → max attempts reached → Pause + dunning email- Each schedule allows
maxRetryAttemptsretries (default 3). - After each decline,
failCountandfailedPaymentCountincrease,lastFailedPaymentDateis set and the next retry is scheduled 24 hours later (nextRetryAt). - Due charges are processed every hour; failed charges are also swept every 6 hours.
- When the retries are exhausted the schedule becomes
paused(isRecurring: false,pausedReason: "Payment failed after 3 retry attempts") and a dunning email is sent once (only when the schedule hassendNotifications: trueand the merchant'sfailedPaymentNoticeEnabledis on). - A successful charge resets
failedPaymentCount,retryCountandnextRetryAt.
Payment Plans#
- A declined installment is retried every
retryIntervalDays(default 3 days) up tomaxRetryAttempts(default 3) attempts, whileretryFailedPaymentsistrue. - While a retry is pending the installment status is
pendingwithnextRetryAtset. - After the last failed attempt the plan becomes
defaulted. - Late fees (if configured) keep accruing on overdue installments and are added to the retried charge. See Payment Plans.
Note: The retry schedule and the action after the last retry are fixed by the platform. There are no dunning-settings endpoints, no configurable retry schedule, no grace period and no
cancel/manual_reviewaction.
Failure Notice Setting#
The only merchant-level dunning control is whether the failed-payment notice is sent. It is part of the merchant's messaging defaults.
Get Messaging Defaults#
curl https://uat.auxcore.net/api/v1/merchants/c1a7e5d2-3b4f-4e6a-9c8d-7f0b1a2e3d45/messaging-defaults \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": {
"successfulPaymentReceiptEnabled": true,
"recurringPaymentReminderEnabled": true,
"failedPaymentNoticeEnabled": true,
"usingDefaults": true
}
}Update Messaging Defaults#
curl -X PUT https://uat.auxcore.net/api/v1/merchants/c1a7e5d2-3b4f-4e6a-9c8d-7f0b1a2e3d45/messaging-defaults \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{ "failedPaymentNoticeEnabled": false }'All three flags are optional booleans; omitted flags keep their value. Admin roles can read and change any merchant; merchant users only their own merchant. Any other caller gets 403 ({ "success": false, "message": "..." }).
Setting failedPaymentNoticeEnabled to false suppresses the dunning email. Per-schedule notifications can also be off (sendNotifications: false on the schedule).
Monitor Failed Payments#
There is no dedicated failed-payments endpoint. Use these instead:
GET /api/v1/recurring/overview—data.failedis the number of schedules with at least one failed payment.GET /api/v1/recurring/:id—failedPaymentCount,retryCount,maxRetryAttempts,nextRetryAt,lastFailedPaymentDate,pausedReason.GET /api/v1/recurring/:id/schedule— cycle rows with statusfailed.GET /api/v1/billing/payment-plans?status=defaulted— defaulted payment plans.
Retry Failed Payment#
Reset the retry counters of a subscription so the scheduler retries on its next run. This does not charge immediately; use Charge Now for that. Returns 400 "No failed payments to retry" when failedPaymentCount is 0.
Endpoint#
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/retry-failed \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"Response:
{
"success": true,
"data": {
"id": "8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61",
"status": "active",
"failedPaymentCount": 0,
"retryCount": 0,
"nextRetryAt": "2026-10-01T16:45:00.000Z"
},
"message": "Payment retry initiated successfully"
}Note: A schedule that was auto-paused must also be resumed (
POST /api/v1/recurring/:id/resume) before the scheduler charges it again.
Charge Now#
Charge the next payment immediately.
Endpoint#
Response:
{
"success": true,
"data": { "success": true, "transactionId": "5b9e2d7a-1c3f-4a8e-b6d0-2f4c8a1e7b93" },
"message": "Payment processed successfully"
}A decline returns 400 with error.code PROCESSING_ERROR. A second attempt within 60 seconds is rejected. For payment plans use POST /api/v1/billing/payment-plans/:id/charge-now (decline → 402).
Update the Customer's Card#
Most failures are fixed by a new card.
Send Update Link#
Emails the customer a secure link (valid 24 hours) to replace the card on file.
For payment plans: POST /api/v1/billing/payment-plans/:id/send-method-update-link.
Link a New Card#
Attach a card you collected yourself (PCI vault token). It becomes the default method; the card is not charged.
{ "pciToken": "pci_tok_1a2b3c4d5e6f", "last4": "4242", "brand": "visa" }For payment plans: POST /api/v1/billing/payment-plans/:id/link-payment-method.
Notifications#
AuxCORE does not emit dunning webhook events. Each attempt is an ordinary transaction, so declined attempts appear as declined transactions. Customer emails:
| When | |
|---|---|
| Payment failed | After each failed automatic charge of a subscription |
| Dunning notice | Once, when a subscription is paused after its last retry (unless failedPaymentNoticeEnabled is false) |
| Payment successful | After a successful charge, including a recovered one |
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 |
| Stop recurring (codes 261/262) | Cardholder asked the issuer to stop | Contact the customer; do not retry |
Best Practices#
✅ DO:#
- Watch the overview - Follow up on schedules with failed payments
- Send the update link early - Before the last retry runs
- Resume after fixing - Auto-paused schedules stay paused until resumed
- Keep failure notices on - Customers can only fix what they know about
❌ DON'T:#
- Don't hammer Charge Now - Repeated declines can trigger issuer blocks
- Don't retry stop-recurring declines - The cardholder revoked the authorization
- Don't cancel immediately - A paused schedule can be resumed
Testing Dunning#
# 1. Create a schedule with a card that will decline in the Sandbox, due today
# 2. Charge it now and confirm the decline
curl -X POST https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61/charge-now \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"
# 3. Inspect the retry state
curl https://uat.auxcore.net/api/v1/recurring/8d2f1c4b-6a3e-4f7d-b1c9-0e5a7d3f2b61 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Tenant-ID: your-tenant-id"See Testing for Sandbox decline cards.
Next Steps#
Need help? Contact support@auxcore.net