SaaS and technology · Recurring collections

Subscription delinquency and dunning

How much MRR is stuck in collections, how much was recovered within the cycle and which subscriptions the team needs to chase today, without counting an attempt as debt.

UsageSpecific
EffortMedium
ForSaaS companies with recurring billing that lose customers to payment failures without noticing.
Source

Invoices, attempts and subscriptions from billing

Rule

Cohort by first failure and a one-cycle window

Outcome

Recovery, MRR in collections and a prioritized queue

Activation

CS queue, health score and AI agent

What it solves

  • Involuntary churn separated from voluntary, with each month's recovery rate.
  • A daily queue of subscriptions with money stuck, with reason and next action.
  • Delinquency on the reference date that matches finance.

Business questions it answers

Ask your agent these questions once the case is live.

How much MRR is stuck in collections today?
What is the recovery rate for August's payment failures?
Which subscriptions need a new card and which only need a reminder?
Who is delinquent today and for how many days?
Which decline reasons most often end in cancellation?
How much of this month's churn was involuntary?

What you need

  • Billing connected to Nekt with invoices, payment attempts and subscriptions
  • The collections policy: how many attempts, when access is blocked and when it cancels
  • The gateway's decline codes mapped to categories with an action

What you get

  • A table of failure and recovery events, one row per attempt
  • Monthly recovery rate by cohort, with each month's maturity
  • A daily collections queue by subscription, prioritized
  • An AI agent that answers who owes, how much and since when

Where to activate

CS and finance queue

Daily list of subscriptions with money stuck, with reason, days and invoice link, prioritized by MRR.

Health score

An overdue open invoice goes in as a declared risk signal, next to usage and support.

AI agent via MCP

Answers who is delinquent, for how many days and how much MRR is in collections, from the reference-date snapshot.

Ready to build?

Billing objects already carry almost everything. The work is using the right grain for each question and keeping the block and dunning state, which billing overwrites. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.

The problem

Every declined card attempt becomes a row, and the same invoice can have several before it is paid. Whoever counts rows multiplies delinquency; whoever looks only at current status doesn't see the invoice that failed and was paid days later, nor the one voided at cancellation. The result is involuntary churn mixed with voluntary churn and a CS team that discovers the failure after the customer has already left.

How it is usually done, and the rule

Each row is a mistake that already happened in practice.

The common wayThe rule
01
Counting rows in the declines table as debts.
An attempt is an event, the debt is the invoice

Keep attempts in an events table, one row per attempt, with date, reason and gateway. Delinquency, recovery and the queue count at the invoice or subscription grain. Automatic retries, duplicate slips and reissues are the same debt.

02
Calling recovered only the invoice paid the same week, or looking at today's status.
Recovered means paid within one cycle of the first failure

The month's cohort is the subscriptions with at least one failure in the month, anchored on the month's first failure. Recovered is one with a successful payment within one billing cycle from it: about 30 days monthly, 90 quarterly, one year annual. Every billing interval goes in, each with its own window. In a real base, recovery in closed months sat near half.

03
Comparing the current month with closed months.
A recent month is still maturing

In recent months, the one-cycle window is still open. Flag the month as maturing until the window closes (monthly: end of month plus 31 days) and never read the low rate of an open month as a decline. A weekly reading with a short window is a different indicator and doesn't compare with the monthly one.

04
Treating every decline the same, or grouping the unknown into other.
The decline reason decides the action

Normalize each gateway's decline codes into a single table, with category and whether a retry is worth it. Invalid number, CVC or expiry (incorrect_number, incorrect_cvc, invalid_expiry_month, invalid_expiry_year in Stripe) need a new card; a generic issuer decline or insufficient funds need a retry or a reminder. Codes that arrive with and without a leading zero are the same. A code missing from the table shows as unmapped, never as other, and someone reviews it every week.

05
Sending the whole list of open invoices to the team.
The queue is for those nobody is chasing

The queue takes live subscriptions with an overdue open invoice and no retry scheduled by billing (next_payment_attempt empty in Stripe), plus those canceled by billing in the last 30 days whose last attempt failed and nothing was paid afterwards. While billing is still retrying, it sends its own notice: don't duplicate the contact. The queue is a snapshot, so check the invoice live before chasing.

06
Sorting the queue by invoice creation date.
Priority by recency and reason

A simple ladder works: up to 14 days from the failure, recover now; invalid card, ask for a new card; up to 60 days, resend the charge with the invoice link; beyond that, likely loss. Count days from the due date of the oldest open invoice, not from the last payment, which includes the cycle already paid. Sort by MRR within each priority.

07
Flagging as delinquent someone who was late on some day of the month and already paid.
Official delinquency is the snapshot on the reference date

Delinquent is whoever has a non-canceled charge that is overdue and unpaid on the reference date: month end for closed months, today for the current month. Due today doesn't count yet. There is no grace period: one day late already counts, and severity comes from the days-late bucket. Having been late at some point in the month is a different, historical-only metric. Delinquent is not inactive: the customer stays in the base until cancellation.

08
Removing past_due from MRR and adding it back the next month.
Past_due stays in MRR, flagged

A past_due subscription stays in MRR flagged as in collections until it becomes canceled or unpaid. Removing it and adding it back when paid creates churn and reactivation that never happened. If the company decides to remove it after a grace period (for example, 7 days), the rule is written and the same in every month.

09
Counting churn on the day the card is declined.
Involuntary churn only after the window

A cancellation by billing, or by the team under a delinquency policy, after failures with no payment is involuntary churn. Declare churn only after the recovery window, at the MRR from before the failure. A common policy is to cut off whoever has two or more overdue bills, the oldest more than 60 days late.

10
Assuming every customer more than 30 days late is blocked.
Access blocks need history

Billing and product only store whether the customer is blocked now. Record block and unblock events, via webhook or a daily snapshot, to know how long each customer stayed blocked and whether they paid afterwards. Blocking after a deadline is an operational decision, not automatic: don't infer a block from days late.

Collections queue: priority and action

Days counted from the due date of the subscription's oldest open invoice.

failure up to 14 days agoP1, recover nowreminder with the invoice link
invalid number, CVC or expiryP2, ask for a new cardincorrect_number, incorrect_cvc, invalid_expiry_*
failure between 15 and 60 days agoP2, resend the charge
more than 60 days without paymentP3, likely loss
canceled by billing up to 30 days ago, no payment sinceRecovery window
billing still retryingOut of the queuenext_payment_attempt filled in

Definitions

Monthly failure cohort
subscriptions with at least one declined payment attempt in the month, anchored on the month's first failure
Recovery rate
cohort subscriptions with a successful payment within one cycle of the first failure / cohort subscriptions
MRR in collections
MRR of active subscriptions with an overdue open invoice, on the reference date
Delinquent on the date
customer with any non-canceled charge overdue and unpaid on the reference date, with no grace period
Days late
reference date minus the due date of the oldest open invoice
Involuntary churn
prior-month MRR of subscriptions canceled after a payment failure with no later payment, declared after the recovery window
First-attempt approval
auto-charged invoices paid on the first attempt / auto-charged invoices in the month

Pitfalls that already happened

Declines that multiplied the debt

A dashboard counted rows in the declines table, and the same sale appeared once per retry. Delinquency looked several times larger than it was.

Count invoices and subscriptions; attempts only as events.

An open month read as a drop

The current month's recovery showed well below average and became an alarm, but that month's one-cycle window was still open.

Store maturity on the row and compare only settled months.

The account vanished along with the debt

The customer view only showed accounts with MRR. A subscription canceled by billing for non-payment left the list exactly during the window when it could still be recovered.

Keep subscriptions canceled by billing in the last 30 days in the queue.

Voided invoice, recoverable customer

At cancellation, billing voided the open invoice. The open amount became zero, a reminder made no sense, and the case was dropped as having no debt.

A zero open amount is valid here: approach with reactivation, not a reminder.

Historical flag used as current status

A late-at-some-point-in-the-month column was used as current status and flagged as delinquent customers who had already paid.

Use the snapshot on the reference date and label the other as historical.

Rate recomputed on an incomplete load

The monthly rate ran at a fixed time and sometimes read yesterday's version of the events table, or recomputed on top of a load that had failed.

Trigger after the load, by event, and store on the row the latest failure the source had.

Validated on real data. In Nekt's own Stripe account, invoices that had any decline carry about three declined attempts each, so counting attempts triples delinquency. And more than 8 in 10 of those invoices were paid later, which is recovery, not loss.

Acceptance test

The case is done when every item passes.

Agent package

Paste into Claude, ChatGPT or any client with the Nekt MCP connected.

Full Markdown
Delinquency and dunning
- A payment attempt is an event. Delinquency, recovery and the queue count by invoice or subscription, never by attempt.
- Monthly failure cohort = subscriptions with at least one decline in the month, by the month's first failure.
- Recovered = successful payment within one cycle of the first failure: 30 days monthly, 90 quarterly, 1 year annual.
- A month with an open window is maturing. Don't compare it with settled months.
- Delinquent = non-canceled charge overdue and unpaid on the reference date (closed month end or today). Due today doesn't count. No grace period.
- Delinquent is not inactive. Past_due stays in MRR flagged as in collections.
- Involuntary churn only after the recovery window, at the MRR from before the failure.
- Collections queue: only subscriptions with no retry scheduled by billing, or canceled by billing up to 30 days ago with no payment since.
- Priority: P1 up to 14 days; P2 invalid card or 15 to 60 days; P3 more than 60 days.
- A decline code missing from the table shows as unmapped.
Per-client exceptions:
- <client>: grace period of <days> days before removing past_due from MRR.
- <client>: cut-off policy at <n> overdue bills with the oldest <days> days late.

Variations

Boleto and Pix

With no automatic retry, the ladder is reminders before and after the due date, and a preventive queue lists who is due in the next 7 days.

Collections in the ERP

When the bill lives in the ERP, use days-late buckets and the credit-bureau flag, reducing to one row per invoice and CNPJ (company tax ID) before joining.

Involuntary churn forecast

The delinquency policy becomes the notice queue, and whoever isn't under any rule gets a calibrated churn probability.