Revenue Recognition & R2R
ASC 606, the revenue subledger and the close
ASC 606 in five steps
After this you can apply the revenue-recognition model to SaaS contracts.
Order-to-Cash moves money. Record-to-Report decides what that money means on the income statement and the rulebook is ASC 606The US revenue-recognition standard; cited as the canonical judgment-heavy accounting work to keep human-led rather than hand to an agent, because facts and circumstances vary deal to deal..
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
AI drafts entries and reconciliations; the review gate stays human.
For this role the domain screen will probe whether you actually understand recognition mechanics or just bill correctly and hope the GL sorts itself out. Cursor sells a usage-heavy product where cash and revenue diverge constantly, so the five-step model is not trivia. It is the contract you implement in code and configuration every day.
- 1Identify the contract. A real, approved agreement with enforceable rights, commercial substance and a probable collection. An order in CPQ becomes a contract when both sides commit, which is the event your O2C pipeline has to capture cleanly.
- 2Identify the performance obligations. The distinct promises inside the contract - the subscription, a usage entitlement, onboarding services, a discounted add-on. Each distinct obligation gets recognized on its own pattern.
- 3Determine the transaction price. The total consideration you expect to be entitled to, including discounts, credits and any variable amount such as usage above a commitment.
- 4Allocate the transaction price. Spread that total across the obligations by their standalone selling price (SSP), so a bundled discount lands proportionally rather than all on one line.
- 5Recognize revenue. Book revenue as each obligation is satisfied - over time for a subscription, point-in-time for a one-off or in line with metered consumption for usage.
A customer who prepays $120k for an annual plan gives you $120k of cash on day one and roughly $10k of recognized revenue per month. The other $110k sits in deferred revenue, a liability, until you deliver. The whole reason a revenue subledger exists is that this gap between cash and earned revenue has to be tracked contract by contract, period by period.
Allocating with SSPwhere bundles get interesting
SSP is the price you would charge for an item sold on its own. When a deal bundles a platform subscription with discounted onboarding, you do not honor the line-item prices on the quote. You allocate the total contract price across obligations in proportion to their standalone values, which can move revenue between lines.
- Obligation
- Annual subscription
- List / SSP
- $100,000
- Allocated price
- $92,308
- Pattern
- Ratably over 12 months
- Obligation
- Onboarding (one-off)
- List / SSP
- $20,000
- Allocated price
- $18,462
- Pattern
- On completion
- Obligation
- Contract total
- List / SSP
- $120,000
- Allocated price
- $110,769 + discount
- Pattern
- -
| Obligation | List / SSP | Allocated price | Pattern |
|---|---|---|---|
| Annual subscription | $100,000 | $92,308 | Ratably over 12 months |
| Onboarding (one-off) | $20,000 | $18,462 | On completion |
| Contract total | $120,000 | $110,769 + discount | - |
A $10k bundle discount allocates ~83% to the subscription and ~17% to onboarding by SSP ratio, not where the rep put it on the quote.
Modifications, upgrades and co-termingcontracts rarely sit still
Mid-term changes are the part candidates fumble. The treatment depends on whether the change adds distinct goods or services at their SSP or alters the existing arrangement.
Adds distinct obligations priced at SSP.
Treated as a brand-new contract.
No retrospective effect on the original.
Remaining goods are distinct, but not at SSP.
Blend unrecognized amount with new consideration.
Recognize over the remaining term going forward.
Remaining goods are not distinct from delivered ones.
Re-measure the single obligation.
Book a true-up in the current period.
Co-terming, where a mid-year upsell is aligned to expire with the original contract, usually falls into the prospective bucket: you reset the schedule for the combined remaining term. Get the classification wrong and the timing of recognized revenue is wrong, which is exactly the kind of error an auditor catches.
Why legacy ERPs break on SaaSthe one-to-many problem
Older ERP revenue logic assumes one invoice produces one revenue event. SaaS violates that on the first deal. A single annual invoice spawns twelve monthly recognition entries, an upgrade splits a schedule mid-stream and a usage line generates a recognition pattern that does not match any invoice at all.
If your architecture forces a one-to-one link between invoice and revenue, every modification becomes a manual journal entry and the close gets slower as the business grows. That is the structural reason a dedicated revenue subledger exists and it is worth naming in the interview before they ask.
Cursor's own finance team draws a hard line here. AI assists accountants in verifying the GL and the accounting; it does not autonomously perform rev rec on a contract where the facts and circumstances vary deal to deal. Build tools around processes with clear, deterministic inputs and outputs - contract provisioning, tie-outs - and keep significant-judgment work human. The analogy they use is the one to remember.
I wouldn't tell Cursor or any AI tool, just like I wouldn't tell a junior intern, to go off and do the rev rec for this specific deal.
When walking through a deal, narrate the five steps in order and pause on step four. Most people can recite the steps; few can explain why a bundle discount reallocates revenue by SSP. Work one concrete SSP allocation out loud and you signal that you have actually closed books, not just read the standard.
Takeaway. Revenue follows delivery, not cash: identify obligations, allocate the price by SSP, then recognize each obligation on its own pattern - the gap is why deferred revenue and a subledger exist.
Self-check
QA customer signs a $120k annual deal: a $100k SSP subscription plus $20k SSP onboarding, with a $10k blended discount. How much revenue do you recognize for the subscription in month one?
Usage-based revenue treatment
After this you can recognize revenue correctly for consumption pricing.
Cursor's own pricing is consumption-heavy, which makes usage-based revenue the single most relevant accounting topic for this seat.
Subscription revenue is the easy case: equal slices over time. Usage breaks the tidiness because the amount is not known until customers consume and the standard has specific machinery for amounts you cannot yet pin down.
Variable consideration and the constraintestimate, but only so far
Variable consideration is any part of the price that depends on a future outcome - overage above a commitment, volume tiers, service credits. ASC 606The US revenue-recognition standard; cited as the canonical judgment-heavy accounting work to keep human-led rather than hand to an agent, because facts and circumstances vary deal to deal. says you estimate it, then apply the constraint: you only include an estimate to the extent it is probable a significant reversal will not occur once the uncertainty resolves.
When the amount you have the right to invoice corresponds directly to the value delivered to date, the practical expedient lets you recognize revenue equal to what you can bill. Pure pay-as-you-go usage at a fixed per-unit rate is the textbook fit: meter the period, rate it, recognize what you invoiced. No estimation of future usage required.
That expedient is why most metered usage is straightforward to recognize. The complications arrive the moment a customer prepays.
Prepaid credits and commitmentsdeferred revenue with a meter
- Event
- Customer buys $50k of credits
- Cash / billing
- Invoice $50k
- Revenue
- $0 recognized
- Balance sheet
- Deferred revenue +$50k
- Event
- Customer consumes $12k of usage
- Cash / billing
- No new invoice
- Revenue
- $12k recognized
- Balance sheet
- Deferred revenue −$12k
- Event
- Commitment period ends, $5k unused
- Cash / billing
- No invoice
- Revenue
- Breakage recognized per estimate
- Balance sheet
- Deferred revenue −$5k
| Event | Cash / billing | Revenue | Balance sheet |
|---|---|---|---|
| Customer buys $50k of credits | Invoice $50k | $0 recognized | Deferred revenue +$50k |
| Customer consumes $12k of usage | No new invoice | $12k recognized | Deferred revenue −$12k |
| Commitment period ends, $5k unused | No invoice | Breakage recognized per estimate | Deferred revenue −$5k |
Prepaid credits are deferred revenue drawn down by rated consumption, not by the calendar.
A committed-spend deal - customer promises $600k over the year, drawing it down by usage - combines both worlds. The commitment is recognized as it is consumed and any minimum that goes unused at period end is a true-up you have to book.
True-ups and breakagethe unused portion
- True-up: when actual usage exceeds a committed minimum, you bill and recognize the overage for the period it occurred.
- Breakage: the portion of prepaid credits a customer is not expected to use. You estimate it and recognize it in proportion to the pattern of actual redemptions, rather than waiting for expiry.
- Re-estimation: breakage is an estimate that you revisit each period as redemption behavior becomes clearer, which can move recognized revenue up or down.
From rated event to recognized revenuethe audit trail that has to survive
The piece that separates a finance systems engineer from an accountant is owning the data path. Every rated usage event has to map to a recognition entry that an auditor can trace back to the metered fact.
- 1Metering captures the raw consumption event with a timestamp, customer and quantity.
- 2Rating applies the price book to produce a dollar amount and a rated-event id.
- 3Recognition ties that rated amount to the contract, draws down any prepaid balance and writes a revenue schedule line for the period.
- 4Reconciliation confirms that rated usage, drawn-down deferred revenue and recognized revenue tie out for every contract.
Late-arriving usage events are the classic trap. If consumption for the last day of the period lands after subledger cutoff, you either accrue it or you understate revenue. Your design needs an explicit cutoff and accrual rule, not an implicit "whatever was in the table when the job ran."
Asked how to recognize Cursor-style usage revenue, lead with the right-to-invoice expedient for pure pay-as-you-go, then immediately distinguish prepaid credits and committed spend, which are deferred revenue drawn down by consumption with breakage on the tail. That sequence shows you know which case is easy and exactly where the judgment lives.
Takeaway. Pure metered usage rides the right-to-invoice expedient; prepaid credits and commitments are deferred revenue drawn down by consumption, with breakage estimated under the constraint.
Self-check
QWhich scenario is the clean fit for the right-to-invoice practical expedient?
The revenue subledger
After this you can place the revenue subledger correctly in the architecture.
The single most important architectural call in R2R is where the revenue subledger lives and what it owns.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
The recurring failure modes a finance-systems engineer automates away.
Billing knows how to charge. The GL knows balances. Neither is built to carry contract-level revenue logic - SSP allocations, deferral schedules, modification true-ups. The subledger is the system in between that does.
The three-layer picturebilling → subledger → GL
- Layer
- Billing engine
- Grain
- Invoice / usage line
- Owns
- What to charge, when, metering and rating
- Why it can't absorb the next layer
- Has no concept of performance obligations or deferral schedules
- Layer
- Revenue subledger
- Grain
- Contract obligation / schedule line
- Owns
- SSP allocation, recognition schedules, deferral, modifications
- Why it can't absorb the next layer
- Too detailed to be the GL; that detail is the point
- Layer
- General ledger
- Grain
- Account balance
- Owns
- Summarized journal entries, trial balance, financials
- Why it can't absorb the next layer
- Too coarse to track contract-level revenue over time
| Layer | Grain | Owns | Why it can't absorb the next layer |
|---|---|---|---|
| Billing engine | Invoice / usage line | What to charge, when, metering and rating | Has no concept of performance obligations or deferral schedules |
| Revenue subledger | Contract obligation / schedule line | SSP allocation, recognition schedules, deferral, modifications | Too detailed to be the GL; that detail is the point |
| General ledger | Account balance | Summarized journal entries, trial balance, financials | Too coarse to track contract-level revenue over time |
Each layer hands a summarized view up and keeps line-level detail for itself.
The subledger holds detail the GL is deliberately too coarse to track: every obligation, its schedule, its deferred balance and the history of any modification. It posts summarized journal entries up to the GL - a single deferred-revenue and recognized-revenue movement per period - while retaining the line-level traceability an auditor will ask for.
- Billings
- what was invoiced, tied back to orders and usage
- Deferred revenue
- the liability balance, drawn down on schedule
- Recognized revenue
- what hit the P&L this period, by obligation
- The tie-out
- opening deferred + billings − recognized = closing deferred, every period
If that roll-forward identity doesn't hold, the subledger is wrong before the GL ever sees it.
Build vs. buythe judgment they're testing
This role explicitly tests when to write code versus configure a platform. Native rev-rec inside a billing tool is enough for some businesses and a liability for others.
Contracts are simple - single obligation, ratable subscription.
Few modifications, no multi-element bundles.
Audit scope is light and volume is modest.
You want speed over control and can live with the tool's model.
Multi-element arrangements need real SSP allocation.
Modifications, co-terming and true-ups are frequent.
Usage and subscription mix on the same contract.
SOXSarbanes-Oxley Act. A US law that forces companies to keep auditable controls over any system that affects their financial reporting.-grade audit trails and segregation of duties are required.
As Cursor's first finance systems hire on a greenfield stack, the instinct to architect a perfect subledger on day one is the wrong one. The honest answer is staged: start where native rev-rec covers the contracts you actually sign today, instrument the tie-out reconciliation early and pull the dedicated subledger in when contract complexity - not headcount - demands it.
Draw the three layers and put the hard logic in the middle one explicitly. Say the subledger keeps contract-level detail and posts summarized entries to the GL, then name your build-vs-buy trigger as contract complexity rather than revenue scale. That distinction - complexity, not size - is what a staff-level answer sounds like.
Takeaway. The subledger sits between billing and the GL: it owns SSP allocation, schedules and modifications at contract grain, posts summarized journals upward and the build-vs-buy trigger is contract complexity, not revenue size.
Self-check
QWhy can't the general ledger simply hold the revenue-recognition detail and skip the subledger layer?
Close, consolidation & reporting
After this you can support a fast, auditable period close with systems.
The close is where systems either earn their keep or bury the team in manual reconciliation for a week every month.
A finance systems engineer is judged on how short, repeatable and defensible the close is. The goal is a close that runs on rails and still gives an auditor everything they need.
The close sequencein order, every period
- 1Subledger cutoff. Freeze the period - usage events after the cutoff belong to next month or get accrued.
- 2Accruals. Book amounts earned but not yet invoiced, including late-arriving usage.
- 3Reconciliations. Tie subledger to billing, deferred-revenue roll-forward, cash to bank, intercompany balances.
- 4Journal posting. Push summarized subledger entries into the GL.
- 5Consolidation. Roll up entities, translate currencies, eliminate intercompany.
- 6Reporting. Produce management and statutory reports plus the flux explanations leadership reads.
Multi-entity and multi-currencywhat scaling to global looks like
A company heading toward multi-billion ARR will carry several legal entities and currencies. Consolidation rolls those entities into one set of financials and a NetSuite OneWorld-class capability handles the mechanics: currency translation at the right rates and elimination of transactions between your own entities.
- Currency translation
- convert each entity's local-currency balances to the reporting currency at period rates
- Intercompany elimination
- remove sales and balances between your own entities so revenue isn't double-counted
- Minority / ownership
- consolidate by ownership structure where entities aren't wholly owned
- Roll-up
- combine eliminated, translated entity results into one consolidated statement
Intercompany eliminations are a frequent source of overstated revenue. If your US entity bills your EU entity for shared services and you forget to eliminate it, consolidated revenue is inflated by an internal transaction. Auditors look for this immediately, so the reconciliation that proves eliminations is non-negotiable.
Automating the closewhere the time goes
Shortening the close comes from automating the two slowest steps: reconciliations and flux analysis. Reconciliations that auto-match and flag only exceptions turn a day of tie-outs into a review of the handful that didn't match. Automated flux compares this period to last and to budget, surfacing the variances worth a human explanation.
Roll-forwards finance lives bythe four that come up constantly
- Roll-forward
- ARR
- Identity
- Opening + new + expansion − contraction − churn = closing
- Question it answers
- Is the recurring base growing and from where?
- Roll-forward
- Deferred revenue
- Identity
- Opening + billings − recognized = closing
- Question it answers
- Does the liability tie to what we've billed and earned?
- Roll-forward
- Billings
- Identity
- Invoiced in period, bridged to bookings
- Question it answers
- What did we actually invoice versus book?
- Roll-forward
- Cash
- Identity
- Opening + collections − outflows = closing
- Question it answers
- Did the cash we expected arrive?
| Roll-forward | Identity | Question it answers |
|---|---|---|
| ARR | Opening + new + expansion − contraction − churn = closing | Is the recurring base growing and from where? |
| Deferred revenue | Opening + billings − recognized = closing | Does the liability tie to what we've billed and earned? |
| Billings | Invoiced in period, bridged to bookings | What did we actually invoice versus book? |
| Cash | Opening + collections − outflows = closing | Did the cash we expected arrive? |
Each is a movement story, opening to closing, that leadership and auditors both read.
Controls in an automated closespeed without losing the audit
- Evidence by default: every automated journal carries the inputs, the rule version and a timestamp, so the run is its own audit trail.
- Segregation of duties: the person who configures a recognition rule is not the person who approves the posting, enforced in the system.
- Exception review: automation handles the clean cases and routes only mismatches to a human, who signs off on record.
- Change management: rule changes go through review and are versioned, so an auditor can see what logic produced any past close.
Trusting the data you close onproducers, consumers and a contract
A close is only as defensible as the data feeding it, and that data is owned by other teams. The mental model Cursor's finance team uses is data producers versus data consumers: finance is a consumer; the analytics, engineering and partner teams upstream are producers. Ownership becomes workable when you negotiate an explicit data contract with those producers - and back it with snapshots and diffs as the data changes.
- Completeness
- every event that should land does land - no silently dropped rows feeding the close
- Accuracy
- the values match the source of truth, verified by reconciliation not assumption
- Timeliness
- the data arrives before cutoff, so accruals reflect reality rather than lag
- Snapshot + diff
- snapshots as data changes, with diffs and reconciliations to catch drift - acknowledged as still maturing
Finance can't own upstream data, so it owns the contract around completeness, accuracy and timeliness.
If asked how you'd speed up the close, don't say "more automation." Name the sequence, point at reconciliations and flux as the slow steps and then add the controls clause unprompted: automated, yes, but with evidence, segregation of duties and versioned rules so it still passes audit. Volunteering the controls is what separates a finance engineer from a scripter.
Takeaway. A fast close automates reconciliations and flux while baking in evidence, segregation of duties and versioned rules - and consolidation hinges on currency translation plus intercompany eliminations.
Self-check
SQL for finance reconciliation
After this you can write the queries that prove the books tie out.
The technical screen will hand you finance data and watch you reconcile it in SQL - this is where engineering and accounting meet on the keyboard.
Reconciliation queries are the load-bearing skill. They prove the deferred-revenue roll-forward holds, that usage ties to revenue and that no rows fell through a join. Strong candidates write queries that are also controls: they return zero rows when the books are clean and the exact offenders when they aren't.
Deferred-revenue roll-forwardthe identity, in SQL
with movements as (
select
contract_id,
period_month,
sum(billed_amount) as billings,
sum(recognized_amount) as recognized
from revenue_schedule_line
group by contract_id, period_month
),
rolled as (
select
contract_id,
period_month,
billings,
recognized,
-- opening = prior period's closing, via running balance
coalesce(sum(billings - recognized)
over (partition by contract_id
order by period_month
rows between unbounded preceding and 1 preceding), 0) as opening_deferred
from movements
)
select
contract_id,
period_month,
opening_deferred,
billings,
recognized,
opening_deferred + billings - recognized as closing_deferred
from rolled
order by contract_id, period_month;Three-way reconciliation with drift detectionusage → invoiced → recognized
The query finance trusts is the one that finds the breaks itself. Join the three views by contract and period, then return only the rows where the amounts don't agree within tolerance.
select u.contract_id, u.period_month, u.rated_usage, i.invoiced, r.recognized, i.invoiced - u.rated_usage as bill_drift, r.recognized - i.invoiced as recog_drift from usage_rated u left join invoiced_amt i on i.contract_id = u.contract_id and i.period_month = u.period_month left join recognized_amt r on r.contract_id = u.contract_id and r.period_month = u.period_month where abs(coalesce(i.invoiced, 0) - u.rated_usage) > 0.01 or abs(coalesce(r.recognized, 0) - coalesce(i.invoiced, 0)) > 0.01 order by abs(i.invoiced - u.rated_usage) desc;
When the books tie out, this query is empty. That property makes it a control you can run on a schedule and alert on: any row is an exception that needs a human. Frame your queries this way in the interview - clean state is zero rows - and you signal that you think in controls, not just reports.
Tracing a break through upstream lineagethe row drifts; where did it come from?
Finding a break is half the work. Explaining it means walking the data lineage. A rev-rec booking table rarely sits alone - at Cursor it lands downstream of five or six upstream tables plus the jobs that run between them. When a discrepancy shows up in the rev-rec table, the question is which upstream table introduced it and which change did so.
This is where an agent earns its keep on a deep monolith. Point Cursor at the discrepancy and it can trace the reconciliation issue back to the furthest upstream table: inspecting which tables feed which, which jobs produce which outputs, whether a snapshot existed at the time and which PRs changed how those tables are built - walking the whole history rather than guessing.
Cursor's finance team described doing exactly this on a live reconciliation break.
We're actually able to trace back the reconciliation issues all the way back to the furthest upstream table using Cursor.
Bridges leadership readsexplaining the movement
Bookings, billings, revenue and cash never equal each other in a given period and explaining the gaps is half the job. A bridge query walks from one to the next so finance leadership sees what drove the difference.
- From → To
- Bookings → Billings
- What the gap is
- Signed but not yet invoiced
- Common driver
- Future-dated or milestone billing
- From → To
- Billings → Revenue
- What the gap is
- Invoiced but not yet earned
- Common driver
- Deferred revenue on prepaid terms
- From → To
- Revenue → Cash
- What the gap is
- Earned but not yet collected
- Common driver
- Net-30 terms, AR aging
| From → To | What the gap is | Common driver |
|---|---|---|
| Bookings → Billings | Signed but not yet invoiced | Future-dated or milestone billing |
| Billings → Revenue | Invoiced but not yet earned | Deferred revenue on prepaid terms |
| Revenue → Cash | Earned but not yet collected | Net-30 terms, AR aging |
Each bridge is a query that attributes the delta to named, explainable buckets.
Data-quality controlsthe breaks that corrupt the close
Rated usage with no matching contract or entitlement.
Anti-join usage against active contracts.
Means revenue can't be attributed.
An invoice exists but no revenue schedule was created.
Anti-join invoices against schedule lines.
Means recognized revenue will be understated.
Payments received but not matched to an invoice.
Anti-join payments against applications.
Distorts AR and the cash bridge.
Performance on high-volume usagebillions of metered events
- Partition by period: range-partition usage tables on event date so a monthly reconciliation prunes to one partition instead of scanning history.
- Pre-aggregate: roll raw events into a rated-by-contract-and-period summary table the close queries hit, leaving the firehose untouched.
- Incremental over full-refresh: recompute only the open period plus a short late-arrival window, not the entire fact table every run.
- Push filters down: filter on the partition key before joining, so the planner never materializes the full cross-product.
Without the right context, a model goes to the wrong table or invents one - the hallucination that quietly corrupts a reconciliation. Cursor's finance team fixed this with a custom skill they call the finance assistant: it holds predefined definitions of every internal term and, for each definition, the table that is its canonical source of truth. Reported as super helpful and used heavily. Once it knows the shape of the business - say, self-service customers billed via Stripe versus enterprise on ACH and wire - you stop re-explaining it on every query, and the model stops grounding itself on the wrong source.
If they let you use Cursor on the SQL exercise, use it - but apply judgment out loud. Generate a draft, then say what you're checking: the join grain, null handling on the left joins and whether the tolerance is right. Catching a model's silent inner-join-where-you-needed-a-left-join is exactly the AI authenticity signal this loop screens for.
Takeaway. Write reconciliations as controls that return zero rows when clean: roll-forwards, three-way drift detection and anti-joins for data-quality breaks, partitioned for usage at scale.
Self-check
QIn the three-way reconciliation, why is using LEFT JOINs from the usage view (rather than INNER JOINs) essential for it to work as a control?