Invoices, attempts and subscriptions from billing
Cohort by first failure and a one-cycle window
Recovery, MRR in collections and a prioritized queue
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.
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
Daily list of subscriptions with money stuck, with reason, days and invoice link, prioritized by MRR.
An overdue open invoice goes in as a declared risk signal, next to usage and support.
Answers who is delinquent, for how many days and how much MRR is in collections, from the reference-date snapshot.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Definitions
Pitfalls that already happened
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.
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 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.
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.
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.
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.
Acceptance test
The case is done when every item passes.
- Each subscription appears at most once in each month's failure cohort.
- Recovered + not recovered = cohort, and no month with an open window shows as settled.
- The queue's open amount matches the sum of open invoices in billing for the same subscriptions (difference under 1%).
- No subscription with a retry scheduled by billing is in the queue.
- Delinquency for a closed month doesn't change when the pipeline runs again.
Agent package
Paste into Claude, ChatGPT or any client with the Nekt MCP connected.
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.
Build the "Subscription delinquency and dunning" case in my Nekt workspace following the rules at https://academy.nekt.com/en/industrias/saas/inadimplencia-dunning.md. 1) Find the source tables and confirm the columns the rules use. 2) Create a transformation at the stated grain applying every rule. 3) Run the acceptance test and show me the result of each item. 4) Create the case's context document in the workspace, leaving my clients' exceptions open for me to fill in.
Variations
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.
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.
The delinquency policy becomes the notice queue, and whoever isn't under any rule gets a calibrated churn probability.