Billing subscriptions, items, prices and invoices
End-of-month state compared with the previous month, by customer
MRR movements, NRR and GRR
Close, board and AI agent
What it solves
- The report's MRR matches billing and finance at close.
- Every real of change has a category: new, expansion, contraction, churn or reactivation.
- A closed month's number doesn't change after it has been reported.
Business questions it answers
Ask your agent these questions once the case is live.
What you need
- Billing connected to Nekt (subscriptions, items, prices and invoices)
- A daily history of subscription state, stored starting now
- The rule agreed with finance for annual plans, discounts, usage, delinquency and currency
What you get
- A customer x month table with starting MRR, ending MRR and the classified movement
- NRR, GRR and churn by month, quarter and trailing 12 months
- An MRR waterfall for the close and for the board
- An AI agent that answers revenue questions with the right rule
Where to activate
The month's and quarter's MRR waterfall with NRR and GRR, read from the frozen table.
Answers about churn, expansion and NRR with the customer-month grain and status rule already applied.
A daily list of customers who contracted or left since the end of the previous month, so CS can act before the close.
The rules are settled, but the history has to exist. If billing doesn't keep versions, start the daily snapshot today and rebuild the past from invoices. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.
Billing shows the subscription as it is now: whoever canceled shows up with zero MRR and whoever changed plans shows up with only the new plan. Summing the change log counts movement that came and went in the same month, and comparing subscriptions instead of customers calls a plan change churn. The result is a different NRR in every spreadsheet and a closed month that changes after it has been reported.
How it is usually done, and the rule
Each row is a mistake that already happened in practice.
Compute each customer's MRR on the last day of the month and compare it with the last day of the previous month. Each customer-month falls into a single movement. The raw change log counts back-and-forth changes within the month and, in one real base, inflated movement by about 18%. The month's snapshot uses the last day of the month for every segment, never the last day each segment had a row.
Churn is a customer who had MRR at the end of the previous month and ends the month with no active subscription. A plan change, renewal or subscription swap for the same customer is expansion, contraction or nothing. Migrating the same customer from one product to another can still count as churn on the source and new on the destination in the per-product view, but must be flagged separately so it doesn't appear as logo loss. Economic-group consolidation follows the rule the workspace already has: if the rule is not to consolidate, each billing account is a customer and only the groups listed in the exceptions are merged.
Annual, semiannual, quarterly or non-standard cycle plans go in divided by the months in the cycle (in Stripe, price.unit_amount x quantity divided by the months of price.recurring.interval x interval_count). Prices with billing_scheme = tiered or usage_type = metered have no unit_amount, and the formula returns zero with no error: value that item by the total of the lines on its latest paid invoice (a tiered item produces several lines in the same period, sum them all) or sum the tiers for the contracted quantity. Before moving on, list the items on active subscriptions that ended up with zero MRR: the list must be empty or every case explained. When the source is the invoice, allocate the recurring amount across the accrual months it covers.
Implementation, setup, one-off credit purchases (one_time price), prorations, one-off services, marketplace fees and partner revenue stay out. Usage-based billing (metered price) only counts in MRR up to the contractual minimum; variable usage above it goes to its own usage revenue column, otherwise every swing in consumption becomes expansion or contraction. A recurring discount reduces MRR; declare when a temporary discount starts to count (some only consider open-ended discounts or those lasting more than 3 months).
Active subscriptions go in. Trialing is not MRR. Canceled and incomplete_expired go out, and the filter is mandatory because a canceled subscription still has items and price filled in. Past_due is a business decision: the safest is to keep it in MRR flagged as at risk until it becomes canceled or unpaid. Removing past_due from MRR creates churn and reactivation that never happened when the invoice gets paid. Unpaid is also a declared decision: state whether it leaves MRR and check it against the finance report's criterion, which often keeps unpaid, or the reconciliation won't close. A freeze shows up in Stripe as status paused or pause_collection filled in on the subscription: classify it as a freeze, not as churn.
On cancellation, the customer's current MRR goes to zero. The amount lost is the customer's MRR at the end of the previous month, or the last known value before canceled_at. Zero MRR never means a free customer: it means a customer who left.
A customer with zero MRR at the end of the previous month and more than zero now is new if they never paid and a reactivation if they had MRR in some earlier month. Reactivation doesn't go into the cohort's NRR, because the customer wasn't in the starting base.
Billing exposes the current state, and Stripe's events API only keeps the last few days. A change in quantity or plan on the same subscription disappears. Write a daily snapshot of subscriptions and items, or a history with valid from and valid to, from day one. For the months before the history starts, rebuild from paid invoice lines with a recurring price and no proration, counting each line in the month whose last day falls inside its service period (period.start to period.end). The first month with a snapshot compares two different sources: flag it as the seam month and keep its movement out of the board deck.
After the close, write the month's result as a provisional version and allow a single correction, which becomes final. Later retroactive corrections go in as an adjustment in the month they were discovered, with the reference month recorded, never rewriting the number already reported.
Convert everything to the reporting currency at a declared rate and use the same fixed rate across the whole movement series: with a monthly rate, a foreign-currency customer who didn't change plans shows up as expansion or contraction. If you need the view at realized exchange rates, show the FX effect on a separate line. Check whether the converted column comes through null for foreign currency before summing.
How each customer-month is classified
Comparing the customer's MRR at the end of the previous month (start) with the end of the month (end).
Definitions
Pitfalls that already happened
Items with tiered or metered prices have no unit_amount, and the price x quantity formula counted them as zero. A few of those items accounted for a meaningful share of MRR, and the total came out several points below finance with no error in the query.
Value those items from the latest paid invoice and list active items with zero MRR before closing the month.
Subscriptions with no payment for months were canceled all at once and all the churn landed in a single month.
Close the exit at the earlier of the cancellation date and the last payment plus one cycle.
A model based on the product screen, not on billing, created activations and reactivations that were never charged and churn from customers with no billed MRR.
Rebuild the start and end state from billing only, with valid from and valid to.
When a subscription recovers from a failed charge, billing pushes the cycle start date forward, and long-standing customers looked new.
Anchor the customer's start on the first confirmed payment, never on the cycle date.
The same group with several CNPJs (company tax IDs) or several paying sub-accounts showed up as several active customers and as several churns.
Follow the workspace's consolidation rule: if it consolidates, use the canonical customer and the CNPJ with the highest MRR as the primary one; if it doesn't, merge only the groups listed in the exceptions.
The table was recomputed on every run and the MRR of closed months changed after being presented.
Freeze the closed month and record adjustments in the month they were discovered.
Acceptance test
The case is done when every item passes.
- Each customer-month has exactly one category, and starting MRR + new + reactivation + expansion - contraction - churn = ending MRR, with no difference.
- No item on an active subscription in the month's snapshot is left with zero MRR; tiered and metered items carry a value taken from invoices.
- A closed month's total MRR matches the billing system's or finance's MRR report within 1%, after aligning the unpaid criterion, the exchange rate and customers billed outside the billing system; every remaining difference is explained.
- GRR never exceeds 100% and NRR doesn't change when new customers are added to the month.
- Running the pipeline again doesn't change any number for a month with a final version.
Agent package
Paste into Claude, ChatGPT or any client with the Nekt MCP connected.
MRR movements - Customer MRR = monthly-normalized amount of recurring items on active subscriptions on the last day of the month, net of recurring discounts. Cycles longer than a month divided by the months in the cycle. A tiered or usage item is worth what its latest paid invoice charged. - Outside MRR: implementation, setup, one-off credits (one_time price), prorations, one-off services, marketplace fees and partner revenue. Variable usage above the contractual minimum goes in the usage revenue column. - Status: active goes in; trialing, canceled and incomplete_expired don't. Past_due stays in MRR flagged as at risk until it becomes canceled or unpaid. Unpaid: <in or out>. Paused or pause_collection filled in = freeze, not churn. - Movement = the customer's MRR at month end compared with the end of the previous month. One movement per customer-month: new, reactivation, expansion, contraction, churn or stable. Zero at start and end produces no row. - Churn is at the customer level: only when the customer ends the month with no active subscription. A plan change is not churn. Churn amount = the customer's MRR at the end of the previous month. - Zero MRR doesn't mean a free customer. It means a customer who left. - Reactivation = a customer with zero MRR at the start who paid before. It doesn't go into NRR. - GRR = (starting MRR - contraction - churn) / starting MRR. NRR = (starting MRR + expansion - contraction - churn) / starting MRR. Only customers in the starting base. - Never sum different currencies. Reporting currency: <currency>, fixed rate for the whole series: <declared rate>. - Months before <history start> come from paid invoices by service period. <seam month> is the seam month between sources and doesn't go to the board. - Economic groups: <consolidated or not consolidated>, per the workspace rule. - Closed months come from the frozen table. Don't recompute or quote a closed month's number from another source. Per-client exceptions: - <client>: migration from product <source> to <destination> within 30 days is flagged as a migration, not as logo churn. - <client>: economic group with several CNPJs (company tax IDs) consolidated under CNPJ <primary>. - <client>: billed outside the billing system; add <recurring amount> to MRR from <month>. - <client>: usage price with a contractual minimum of <amount>, which is the part that counts in MRR.
Build the "MRR and its movements, with NRR and GRR" case in my Nekt workspace following the rules at https://academy.nekt.com/en/industrias/saas/mrr-movimentos-nrr-grr.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
The same rule at the customer x product x month grain. Cross-sell shows up as expansion with a new-product flag.
Rebuild the past from paid invoice lines by service period, start the daily subscription snapshot today and flag the seam month between the two sources.
When the contract lives in the CRM, use the recurring amount from the won deal's line items, never the deal's total amount field, and check it against billing.