Overview
Journey’s dunning system automatically handles failed subscription payments through intelligent retry logic, delivery rescheduling, and customer communication. The system is designed to maximize payment recovery rates while minimizing customer friction and churn.Why Dunning Matters
Payment failures are inevitable in subscription businesses:- Credit cards expire - Average card lifespan is 2-3 years
- Insufficient funds - Temporary account balance issues
- Bank declines - Fraud prevention systems, spending limits
- Technical errors - Network timeouts, processor issues
- 20-30% of subscriptions would churn unnecessarily
- Lost revenue from otherwise happy customers
- No recovery mechanism for temporary issues
- 70-80% of failed payments successfully recover (companies with mature dunning processes)*
- Automated communication keeps customers informed
- Delivery rescheduling prevents waste and maintains satisfaction
Subscription Statuses
Journey uses five subscription statuses to manage the dunning lifecycle:ACTIVE - Successful Payments
ACTIVE - Successful Payments
- New subscription created with successful payment
- Failed payment successfully retries and settles
- Customer updates payment method and payment succeeds
- Future deliveries scheduled normally
- Payment charged according to billing frequency
- No retry attempts needed
PAST_DUE - Insufficient Funds
PAST_DUE - Insufficient Funds
- Payment processor returns “insufficient funds” error code
- Typically temporary - customer may receive paycheck soon
- Delivery rescheduled to next available date
- Daily retry attempts (or as configured)
- Email notification on first failure
- Reminder email every 4th retry attempt
- Past due indicates a temporary issue (no money right now)
- More lenient retry schedule
- Higher recovery rate (70-80%)
- Receives friendly reminder email: “Payment didn’t go through, we’ll try again”
- Delivery automatically moved to avoid waste
- No service interruption if payment succeeds within retry window
ERROR - Card/Bank Decline
ERROR - Card/Bank Decline
- Expired credit card
- Card reported lost/stolen
- Bank fraud detection
- Payment processor errors
- Delivery rescheduled to next available date
- Daily retry attempts (or as configured)
- Email notification on first failure: “Please update payment method”
- Reminder email every 4th retry attempt
- More urgent tone than PAST_DUE
- Indicates customer action needed (update payment method)
- Lower automatic recovery rate (20-30%)
- Requires customer intervention for resolution
- Receives email with link to update payment method
- Clear call-to-action to prevent cancellation
- Delivery held until payment resolves
EXPIRED - Max Retries Exceeded
EXPIRED - Max Retries Exceeded
- Settling attempts reaches the merchant’s max retry threshold (typically 20)
- No successful payment after retry period (typically 20 days)
- Subscription marked as expired
- Future deliveries cancelled
- Final notification email sent
- Payment attempts cease
- Stock unreserved for all failed orders
- If customer wants to reactivate, they must create a new subscription
- Old subscription remains in EXPIRED state for record-keeping
- Receives final cancellation email
- Account suspended until new subscription created
- Can restart anytime with updated payment method
ON_HOLD - Customer Paused
ON_HOLD - Customer Paused
- Customer clicks “Pause Subscription” in customer portal
- Temporary hold for vacation, travel, etc.
- No payment attempts made
- Future deliveries cancelled automatically
- No dunning emails sent
- Subscription remains paused until customer resumes
- Full control to pause and resume
- No charges while paused
- Easy reactivation when ready
Intelligent Retry Logic
Journey’s dunning system adapts retry behavior based on the type of payment failure and whether the order has already been delivered.Daily Retry Schedule
Respectful Retry Timing
One Attempt Per Day
Automatic Rescheduling
Retry Charge
Understanding Payment Failures
The system intelligently classifies payment failures into two categories, each requiring a different response:- Temporary Issues (PAST_DUE)
- Customer Action Required (ERROR)
- Insufficient funds in the account
- Card temporarily declined by the bank
- A temporary processing issue
- These are usually temporary problems the customer may not even realize they have
- High probability of recovery with a simple retry
- The customer is often aware of the issue (low balance) and may resolve it themselves
- These represent pure revenue recovery opportunities
Retry Attempt Limits
The system tracks how many times it has attempted to collect payment for each order. This prevents infinite retry loops while giving customers multiple opportunities to resolve their payment issues. How It Works:- Each retry attempt is logged and counted
- After reaching the maximum number of attempts (default: 20 attempts, configurable per business), the system stops retrying
- When the retry limit is reached, the subscription is marked as “expired” and cancelled
- A final cancellation notification is automatically sent to the customer
- More attempts = Higher recovery rate, but longer customer experience limbo
- Fewer attempts = Faster resolution, but may lose recoverable payments
Customer Communication Strategy
Journey automatically sends emails at key points in the dunning lifecycle to keep customers informed and drive payment resolution.Communication Timeline
First Failure Notification
First Failure Notification
SUBSCRIPTION_STATUS_SET_TO_PAST_DUE_FOR_THE_FIRST_TIME or SUBSCRIPTION_STATUS_SET_TO_ERROR_FOR_THE_FIRST_TIMETiming: Immediately after first payment failureTone: Friendly and helpfulContent:- Explanation that payment didn’t go through
- Reason (insufficient funds vs. card issue)
- For PAST_DUE: “We’ll try again soon”
- For ERROR: “Please update your payment method”
- Link to customer portal to update payment method
- Delivery rescheduled date
- Contact support information
Hi [Customer Name], We tried to process your payment of [Amount] for your upcoming delivery, but it didn’t go through due to insufficient funds. Don’t worry - we’ll automatically try again tomorrow. Your delivery has been rescheduled to [New Date] to give the payment time to process. If you’d like to update your payment method, you can do so here: [Link] Questions? Contact us at [Email]Example Message (ERROR):
Hi [Customer Name], We tried to process your payment of [Amount], but your card was declined. Action needed: Please update your payment method to keep your subscription active. Update Payment Method: [Link] Your delivery is on hold until we can process payment successfully. We’ll continue trying daily for the next 20 days. Questions? Contact us at [Email]
Every 4th Attempt Reminder
Every 4th Attempt Reminder
SUBSCRIPTION_STATUS_STILL_ON_ERROR_EVERY_FOURTH_TIMETiming: On attempts 4, 8, 12, 16, 20Purpose: Periodic reminder without overwhelming the customerTone: Progressively more urgentContent:- Number of attempts so far
- Days until cancellation
- Strong call-to-action
- Link to update payment method
- Current delivery status
Hi [Customer Name], We’ve now tried 8 times to process your payment without success. You have 12 days remaining before your subscription is cancelled. Please update your payment method now to avoid interruption: [Link] Need help? Reply to this email or call [Phone]Example Message (Attempt 16):
URGENT: Only 4 days left - [Customer Name] We’ve tried 16 times to process your payment. After 4 more attempts, your subscription will be permanently cancelled. Update payment method NOW: [Link] This is your final reminder before cancellation.
Final Expiration Notice
Final Expiration Notice
SUBSCRIPTION_STATUS_SET_TO_EXPIREDTiming: After reaching dunning_settling_attempts limitTone: Apologetic but firmContent:- Subscription has been cancelled
- Reason (max retries exceeded)
- How to reactivate (create new subscription)
- Thank you message
- Feedback request (optional)
Hi [Customer Name], We’re sorry to see you go. After 20 unsuccessful payment attempts, we’ve had to cancel your subscription. What this means:Want to come back? Simply visit [Link] and create a new subscription with an updated payment method. We’d love to hear why you left: [Feedback Link] Thank you for being a customer!
- No future deliveries will be sent
- Your account remains active for viewing history
- You can create a new subscription anytime
Communication Best Practices
- Email Design
- Tone & Voice
- Conversion Tactics
- First failure: “Payment issue with your [Product] subscription”
- 4th attempt: “Reminder: Update payment method”
- 8th attempt: “Action needed: [Days] days until cancellation”
- 16th attempt: “URGENT: Update payment by [Date]”
- Expiration: “Your subscription has been cancelled”
- Use customer’s first name
- Clear subject line indicating urgency
- Mobile-responsive HTML design
- Prominent call-to-action button
- Include support contact information
- Merchant branding (logo, colors)
Technical Implementation
Automated Cron Job
The dunning system runs via thepayment_for_delivery.py management command, executed daily by cron.
Cron Schedule
Multi-Tenant Execution
Error Handling
/var/log/cron.log. Individual tenant failures don’t stop other tenants from processing.Processing Functions
- PAST_DUE Processing
- ERROR Processing
- Failed Invoice Cleanup
process_deliveries_with_past_due_subscription_status_and_failed_payment_status()Query Filters:- Subscription status:
ACTIVEorPAST_DUE - Payment status:
FAILED - Date range: Last 30 days to +14 days ahead
- Not cancelled
- Check if already retried today → Skip if yes
- If delivery already completed → Retry payment
- If delivery not completed → Reschedule to next date, then retry
- If max attempts reached → Set to
EXPIRED - Every 4th attempt → Send reminder email
Date Range Strategy
- Deliveries from the past month get retry attempts
- Future deliveries within 14 days are prepared for payment
- Old deliveries eventually get cancelled by
process_failed_invoices()
Stock Management Integration
Dunning integrates with Journey’s stock management system to handle inventory correctly during payment retries.Stock Reserved on Order Creation
Stock Fulfilled on Payment Success
Stock Unreserved on Payment Failure
Stock Unreserved on Delivery Cancellation
Monitoring & Reporting
Dunning Report
Access the live dunning report at/dashboard/reports → “Dunning subscriptions”
Shows:
- Subscription status (PAST_DUE or ERROR)
- Customer name and email
- Subscription ID (clickable link to admin)
- Number of settling attempts
- Sorted by: Settling attempts DESC (most urgent first)
- Proactive customer outreach
- Identify subscriptions close to expiration
- Manual payment method updates via admin
- Customer success intervention
Cron Logging
All dunning execution is logged to/var/log/cron.log:
Sentry Integration
All dunning errors are automatically captured to Sentry with context:- Tenant schema name
- Function that failed
- Delivery/payment/subscription IDs
- Full stack trace
- Payment processor response
Merchant Configuration
Each merchant can customize dunning behavior via the admin interface.dunning_settling_attempts
dunning_settling_attempts
merchant.dunning_settling_attemptsDefault: 20Description: Maximum number of retry attempts before subscription expires.Configuration:- Higher value = More recovery opportunities, longer retry period
- Lower value = Faster expiration, cleaner subscriber list
failed_payment_cancelled_days
failed_payment_cancelled_days
merchant.failed_payment_cancelled_daysDefault: 20Description: Days before failed deliveries are automatically cancelled.Configuration:- Prevents infinite delivery rescheduling
- Cleans up zombie deliveries
- Frees reserved stock
dunning_settling_attempts.Email Templates
Email Templates
/admin/communication/message/.Key Templates:- PAST_DUE First Time - Friendly insufficient funds notice
- ERROR First Time - Urgent payment method update request
- Every 4th Attempt - Progressive urgency reminders
- EXPIRED - Final cancellation notice
{{ customer_object.full_name }}{{ merchant_object.name }}{{ delivery_object.delivery_date }}{{ subscription_object.id }}- Custom context variables
Best Practices
For Merchants
For Merchants
- Review subscriptions with 10+ attempts
- Proactively call high-value customers at risk
- Offer payment plan or pause option
- Send test emails to yourself
- Check mobile rendering
- Verify links work correctly
- A/B test subject lines
- Higher-value subscriptions → More attempts (25-30)
- Lower-value subscriptions → Fewer attempts (15-20)
- Consider customer acquisition cost (CAC)
- Credit cards
- Debit cards
- Bank transfers
- Digital wallets (Apple Pay, Google Pay)
- Train support team on dunning process
- Provide self-service payment method update
- Offer pause instead of cancel
- Consider win-back campaigns for EXPIRED
For Developers
For Developers
- Always wrap payment calls in try/except
- Log all failures to Sentry
- Don’t let one failure stop batch processing
- Use
@exception_via_slackdecorator for critical functions
- Test with all three payment processors (Rapyd, Reepay, Straumur)
- Simulate insufficient funds (response code 51)
- Simulate card declines
- Test expiration at exact threshold
- Verify stock unreservation
- Index
payment.settling_attemptscolumn - Index
subscription.subscription_statuscolumn - Optimize queries with proper joins
- Use tenant context correctly
- Set up Sentry alerts for dunning failures
- Monitor recovery rate (settled after failure)
- Track average attempts to recovery
- Alert on processing time > 10 minutes
Recovery Optimization
Recovery Optimization
- Retry after 8 AM (customer may have deposited paycheck)
- Avoid weekends for initial failures (check deposit timing)
- Consider payday schedules (1st and 15th)
- First email: Informative, not urgent
- 4th attempt: Gentle reminder
- 8th attempt: Moderate urgency
- 12th+ attempts: High urgency
- 16th+ attempts: Final warning
- Allow customers to update payment method themselves
- Accept multiple backup payment methods
- Automatically try backup method after primary fails
- Notify when card is expiring (before it fails)
- Small discount for updating payment method
- Free delivery if resolved within 3 days
- Loyalty points for maintaining active status
- Win-back offers for EXPIRED subscriptions
Troubleshooting
Subscriptions Not Recovering
Subscriptions Not Recovering
- PAST_DUE subscriptions staying in that status
- Settling attempts incrementing but not expiring
- Customers complaining about repeated charges
- Check cron job is running:
grep "payment-and-delivery" /var/log/cron.log - Check Sentry for errors during payment processing
- Verify payment processor credentials are valid
- Check customer has valid payment method
- Restart cron service if jobs aren’t running
- Update payment processor API credentials
- Contact customer to update payment method
- Check for rate limiting from payment processor
Too Many Reminder Emails
Too Many Reminder Emails
- Customers receiving multiple emails per day
- Spam complaints from customers
- Check
payment.last_attemptdates - should be once per day - Verify
settling_attempts % 4 == 0logic for reminders - Check for duplicate cron jobs
- Fix daily attempt check logic
- Consolidate duplicate cron entries
- Add rate limiting to email sending
- Review communication event triggers
Stock Not Unreserving
Stock Not Unreserving
- Inventory showing as reserved for cancelled deliveries
- Out of stock errors despite physical inventory
- Check
process_failed_invoices()is running - Verify stock unreservation calls in cancellation flow
- Check for errors in stock management system
- Manually unreserve stock via admin interface
- Run stock reconciliation script
- Fix stock unreservation error handling
- Add logging to stock management operations
Subscriptions Expiring Too Soon
Subscriptions Expiring Too Soon
- Subscriptions reaching EXPIRED before customer can act
- High churn rate from dunning
- Check
merchant.dunning_settling_attemptsvalue - Verify email templates are being sent
- Check email delivery rates (Postmark dashboard)
- Review customer feedback
- Increase
dunning_settling_attempts(20 → 25) - Improve email subject lines for better open rates
- Add SMS notifications for high-value customers
- Offer pause option before cancellation
- Call high-value customers at risk
Performance Metrics
Track these metrics to optimize dunning effectiveness: Recovery Rate:- Open rate: >40%
- Click-through rate: >10%
- Payment method update rate: >15%