Step 1 — Resume the ledger

Read .kortix/memory/payment-recovery-ledger.md. For every subscription already tracked, note its current rung, the timestamp of its last action, and its next-eligible-escalation time. Anything not yet on the ledger is a candidate for Step 2.

Step 2 — Pull failed invoices and subscription state from Stripe

Query Stripe for invoices in a failed/past-due state and their parent subscriptions. For each:
  • New failure (not on the ledger) → start at rung 1 (smart retry).
  • Already on the ledger → check whether now >= next-eligible time; if not, leave it alone this run.
  • No longer failing (invoice paid, subscription active/current) → go to Step 6 (close out), regardless of rung.

Step 3 — The ladder

RungNameActionMinimum wait before this rung
1Smart retryRetry the failed charge against the existing payment method via Stripe (off-session), no email sent yetImmediately on first failure
2Payment reminderFriendly email: the charge didn't go through, here's the amount and a pay link24h after rung 1 if still failing
3Update-your-card noticeFirmer email naming the likely cause (expired/declined card) with a direct link to update the payment method48h after rung 2 if still failing
4Final noticeClear, professional email stating this is the last automated reminder before the account needs manual attention72h after rung 3 if still failing
A subscription advances at most one rung per run, and only once its minimum wait has elapsed. Never send two rungs' worth of email in the same run, and never re-send the same rung.

Step 4 — Send the rung's email

Send the exact email for the current rung via {{dunning_channel}}, addressed to the subscription's billing contact. Keep the tone matched to the rung — rung 2 is a nudge, rung 4 is unambiguous but still professional, never threatening. Every send is logged to the ledger with the rung and timestamp.

Step 5 — Rung 4 is the ceiling

Once a subscription has received the final notice and the invoice is still unpaid, do not create a rung 5. Mark it awaiting-human on the ledger and surface it in the Slack summary every run until a person acts or it pays. Never cancel the subscription, issue a credit, or process a refund — that decision, and the action, belongs to a human.

Step 6 — Close out on payment

If a tracked subscription's invoice has been paid (checked fresh from Stripe every run, not assumed), mark it recovered on the ledger with the rung it was on when it cleared, stop sending it anything, and report it as a recovery in the summary.

Step 7 — Post the summary

Post one message per run to {{alert_channel}}: subscriptions that advanced a rung (with new rung), subscriptions newly at awaiting-human, and subscriptions that recovered since the last run. Omit subscriptions with no change.

Step 8 — Update the ledger

Write the full current state back to .kortix/memory/payment-recovery-ledger.md (see <ledger-format>) before ending the turn.
Dunning escalation ladder — Kortix Marketplace | Kortix