Reminder automation should answer one question before every send: does this invoice still require customer action?
Suppress reminders when the invoice is no longer collectible
- Paid: stop immediately.
- Cancelled or waived: stop.
- Paid through another accepted route: stop.
- Membership or service intentionally frozen: stop or follow the merchant's specific policy.
Suppress aggressive follow-up while payment is unresolved
If the latest M-PESA Express attempt is Pending or Unknown, do not send a second payment request merely because a reminder job reached its scheduled time.
Use the stored CheckoutRequestID to query the unresolved STK request where appropriate, then decide whether a new attempt is safe.
Evaluate state at send time, not schedule time
A reminder created yesterday may be wrong today. The worker should load the invoice and latest relevant attempt immediately before delivery.
This protects against a payment arriving between scheduling and execution.
Make reminder jobs idempotent
Give each intended reminder a stable key such as invoice + stage + channel. If a worker retries after a timeout, it should not send the same reminder twice.
Keep copy outside the state machine
The billing engine should decide that a due-date reminder is eligible. A message template service can decide the exact SMS, WhatsApp or email wording.
For copy-ready examples, see the payment-reminder templates guide.
Log why a reminder was sent or suppressed
- invoice state at evaluation;
- latest attempt state;
- reminder stage;
- channel;
- suppression reason, if any;
- delivery result.
This makes support investigations much easier than a generic “message sent” audit log.
A reminder decision table is safer than a cron schedule
A daily scheduler can decide which invoices are candidates for follow-up, but eligibility should come from current state. A useful decision table combines invoice status with the latest payment-attempt status so the same scheduled job can behave differently for different customers.
- Due + no attempt: reminder may be eligible.
- Due + final failed/expired attempt: reminder or retry path may be eligible.
- Due + Pending/Unknown attempt: suppress and verify first.
- Paid, cancelled or externally satisfied: suppress permanently.
Handle race conditions deliberately
A common failure mode is a payment succeeding seconds after a reminder worker loaded the invoice. Re-read the invoice inside the send transaction or immediately before delivery, and record a reminder idempotency key. That reduces the chance of sending “pay now” after the customer has already completed payment.
For larger systems, treat the suppression reason as data. It becomes useful for debugging reminder noise, measuring how often late payment events cancel scheduled messages and proving why a particular customer was or was not contacted.
Source
Safaricom M-PESA Express Query API: https://developer.safaricom.co.ke/apis/MpesaExpressQuery



