Dunning should be a policy engine, not a fixed reminder sequence
A recurring business needs rules for what happens after an invoice becomes due and remains unpaid. Those rules should be configurable because a gym, SaaS product, ISP and school do not have the same customer relationship or service consequence.
The general failed-payment recovery guide explains the lifecycle. This guide focuses on how to configure the policy.
1. Define the entry condition
Do not start dunning merely because a scheduled payment job ran. Start when the invoice is due and still unsatisfied under the merchant's policy.
Possible entry rules:
- On due date if no payment attempt exists.
- After a final failed or expired attempt.
- After a short post-due buffer for a merchant that does not chase immediately.
A Pending or Unknown attempt should usually suppress aggressive recovery until verified.
2. Configure timing independently from message copy
A policy can define stages such as pre-due, due, overdue, grace-ending and post-grace without hard-coding the exact message into the state machine.
That lets the merchant change SMS, WhatsApp or email copy without changing retry logic.
3. Set channel order
A merchant may prefer email first for SaaS, SMS first for memberships, or a mix. The policy should decide which channel is eligible at each stage and enforce frequency limits.
For example customer messages at each stage, see the guide to making monthly M-PESA payments easier.
4. Set retry limits
Define how many new payment attempts can be created inside one billing period and what counts as an attempt.
A retry limit protects customers and reduces provider noise. It should not include status queries, because querying an unresolved attempt does not move money.
5. Make retry timing depend on failure reason
Cancellation, wrong PIN, timeout and insufficient balance are different outcomes. The retry guide owns the specific timing recommendations. The dunning policy should consume a normalized failure category and decide which next actions are allowed.
6. Configure wallet fallback
A merchant can allow another enabled wallet after a previous attempt is final. The policy should prevent wallet switching while the earlier attempt is Unknown.
7. Define the grace period
The policy should know when grace begins, when it ends and what happens if a payment is unresolved at the cutoff.
Grace is a commercial rule. It should not be reset automatically every time a customer creates another payment attempt.
8. Separate payment recovery from service consequences
At the end of grace, the merchant may suspend access, limit features, pause service or send the account to review.
The dunning engine should emit the eligible action. The merchant's product or operations system should own the actual service state.
9. Define reactivation
A dunning policy is incomplete if it describes suspension but not recovery.
When payment succeeds, define:
- how quickly reminders stop;
- whether service is restored automatically;
- whether staff review is required;
- whether the next renewal date changes.
10. Add global stop conditions
- Invoice paid.
- Invoice cancelled or waived.
- Customer/account paused under an approved policy.
- Persistent payment uncertainty escalated to manual review.
- Merchant-level incident suppresses collection.
These stop conditions should override scheduled actions.
An example policy object
A configurable implementation might expose fields such as:
- pre_due_days: 2
- grace_days: 4
- max_payment_attempts: 3
- alternate_wallet_allowed: true
- unknown_state_blocks_retry: true
- suspend_after_grace: true
- reactivate_on_verified_payment: true
Those values are illustrative, not recommended defaults. The merchant should choose them based on product economics and customer expectations.
What to measure
- Share paid before dunning starts.
- Recovery rate by stage.
- Attempts per recovered invoice.
- Messages per recovered invoice.
- Wallet-switch recovery.
- Unknown-state blocks.
- Suspension and reactivation rates.
- Manual overrides.
A configurable policy should make those outcomes observable so the merchant can tune the rules instead of guessing.
Sources
- Safaricom M-PESA Express Query API: https://developer.safaricom.co.ke/apis/MpesaExpressQuery
- Safaricom Daraja API catalogue: https://developer.safaricom.co.ke/apis



