← All articles

GTM Operations

The CRM Says $4.2M. Finance Says $3.6M. The Board Hears a Third Number.

Three systems, three revenue numbers, one board meeting. The fix is a field-level crosswalk you build in six rungs, not a bigger spreadsheet.

· 13 min read

CRM says $4.2M closed this quarter. Finance says $3.6M. The board deck, built the night before by someone splitting the difference under pressure, says $3.9M. Same company, same quarter, three numbers. Nobody in the room is lying. They are all reading a different field.

That $600K gap between the CRM and Finance is a definition mismatch nobody wrote down, not a rounding error and not fraud. The CRM counts an opportunity as revenue on close date. Finance counts it when the contract is signed and the service starts, which can be a month later and a different quarter entirely. Add multi-year deals booked as total contract value in Salesforce but recognized as annual in the GL, and the gap stops being a surprise. It becomes structural. When teams argue about which number is right, what they are missing is ownership: if two people can defend two figures, no one owns the translation between them.

$600K
Structural gap between CRM and Finance on the same quarter
3 clocks
Close date, recognition date, and whenever the deck was built
5%
Variance band I hold teams to, matching the sub-5% forecast standard

Here is what I build instead of a bigger meeting: a field-level crosswalk, stood up in six rungs. Each rung is shippable on its own and each earns the next, so a team frozen at the 11pm guess has a first step it can take this week. This is the framework. Scroll it, then I will walk every rung with the math and the queries underneath.

Build it bottom to topThe reconciliation layer, in six rungs
  1. L5Board number = bottom of the bridge$3.6M

    On the last day of the period the board figure is the last row of the recalculated bridge. No hand reconciliation, no hidden tab, no invented third number.

  2. L4Snapshot the table dailydaily diff

    Diff today against yesterday and attribute every dollar of gap movement to a specific deal and field, so the reconciliation is never stale by lunch and never a memory contest.

  3. L3Build the ARR bridge as a query$600K

    Start from SF booked Amount and walk line by line to Finance recognized. Every adjustment is a named, defensible step with SOQL behind it. The $600K decomposes into three owned lines.

  4. L2Write the field-level crosswalk1 row / field

    One row per CRM field: its Finance counterpart, the transformation rule, and a named owner. The artifact is a table a second person can audit, not a conversation.

  5. L1Trace one deal through three systems1 deal

    Pull a single closed deal and find where Amount, recognized revenue, and the board figure diverge. That one trace surfaces the fields your crosswalk needs and the definition nobody agreed to in writing.

  6. L0The 11pm guess$3.9M

    One person reconciles two systems by hand the night before the board meeting. The number lives in their head and a hidden tab. This is where most teams sit, and it is the rung every rung above deletes.

Locate yourself on that ladder. The 11pm guess is L0, and most teams live there without naming it. Every rung above subtracts a specific failure: L1 kills the unexamined definition, L2 kills the memory-based reconciliation, L3 kills the shrug when the board asks why, L4 kills the staleness, L5 kills the third number. By the top the figure you carry into the board meeting is one you can defend line by line.

The three numbers come from three clocks

Walk the same deal through the three systems and watch it change shape.

SystemWhat it countsWhen it counts it
SalesforceAmount on the opportunityCloseDate
Finance / GLRecognized revenueContract start, ratably
Board deckWhatever survived the copy-pasteWhenever the deck was built

A $360K three-year deal closes March 30. Salesforce books $360K in Q1 on the Amount field. Finance sees $120K of annual value and does not start recognizing until the license key activates on April 8, which lands in Q2. So the CRM shows $360K in Q1 and Finance shows $0 in Q1 for the same deal. Multiply that shape across forty deals and you get your $600K. This is rung L1: one trace, and the divergence is already visible.

One deal, three clocks A $360K deal is $360K, $0, or something in between depending on which field you read
Salesforce$360K TCV on CloseDate (Q1)Finance / GL$0 in Q1, activates Apr 8 (Q2)Board decksplit the difference, 11pmCrosswalk / ARR bridgeevery dollar of gap named and owned
Same opportunity. Salesforce books TCV on close date, Finance recognizes annual value on activation, and the board deck reads whatever survived the 11pm copy-paste.

The board number is the worst of the three because it has no clock at all. It is a human reconciling two systems by hand at 11pm, and the reconciliation lives in that person’s head and a hidden tab. That is not a small operational annoyance. Gartner puts the average cost of poor data quality at $15M a year per organization, and Experian’s 2024 data-management study found 55% of businesses say low-quality data undermines confidence in the systems that report it. A revenue number nobody can trace is exactly the kind of data that erodes trust in the room where trust matters most.

The trap that makes this feel unsolvable is the instinct to pick a winner. Sales leadership defends the CRM number because that is what reps closed and what comp is paid on. Finance defends the GL number because that is what the auditors will accept and what the cash reflects. Both are correct for their own purpose, and any meeting that tries to declare one of them the real number ends in resentment and a third number invented afterward. The gap is not a disagreement to resolve, it is a translation to document. Once you accept that, the work stops being a negotiation and becomes an engineering task, which is the only kind of task that stays solved.

The fix is a crosswalk, not a bigger meeting

You do not close this gap by arguing about whose number is right in the QBR. You close it by building a field-level crosswalk that maps every CRM field to its Finance counterpart, with the transformation rule written down. This is rung L2, and it is the same discipline as computing board metrics at the source: the definition lives in the query, not in a person’s memory.

The crosswalk is a real artifact, one row per field, auditable by a second person:

CRM fieldFinance counterpartTransformation ruleOwner
Opportunity.AmountRecognized revenueSplit TCV to annual, defer to activationRevOps + Rev Rec
Opportunity.CloseDateRev-rec start dateUse License_Key_Activation__c, not closeRev Rec
Multi-year flagContract term monthsTCV divided by term, times 12, is annualRev Rec
StageName = Closed WonBooked, not yet recognizedHolds in a bridge line until activationRevOps

Every row has an owner because revenue leakage lives anywhere a record, owner, stage, or responsibility changes hands, and a crosswalk with no owner per row is a crosswalk that rots the first time a field definition drifts. Naming the owner is what makes the artifact survive the quarter.

Build the ARR bridge as a query

Rung L3 turns the crosswalk into a running number. I build ours as an ARR bridge: a single query that starts from Salesforce bookings and walks, line by line, to the Finance ARR number. Every adjustment is a named, defensible step.

SF booked Amount (CloseDate basis)         $4,200,000
  - multi-year TCV booked as single year   ($480,000)
  - deals closed but not yet activated      ($240,000)
  + prior-quarter activations landing now    $120,000
  = Finance recognized (period basis)       $3,600,000

Now the $600K decomposes cleanly: $480K of multi-year timing, plus $240K of activation lag, minus $120K of catch-up. That reconciles exactly to the gap in the stat tiles at the top, and each line has an owner and a SOQL query behind it. When the board asks why the numbers differ, the answer is four lines, not a shrug.

The ARR bridge: SF bookings to Finance recognized
Each bar is a named, owned adjustment. The $600K gap decomposes into multi-year timing, activation lag, and a prior-period catch-up, none of them a mystery.
View as table
ItemValue
SF booked4,200K
Multi-year TCV480K
Not yet activated240K
Prior-qtr catch-up120K
Finance recognized3,600K

The SOQL behind the two largest bridge lines is not exotic. Multi-year TCV and the not-yet-activated deals both come straight from fields you already have:

-- Multi-year TCV booked this period that should recognize as annual
SELECT Id, Name, Amount, Contract_Term_Months__c,
       Amount / Contract_Term_Months__c * 12 AS annual_recognized
FROM Opportunity
WHERE IsWon = true
  AND CloseDate = THIS_QUARTER
  AND Contract_Term_Months__c > 12;

-- Closed but not yet activated: sits in the bridge until the key turns on
SELECT Id, Name, Amount, License_Key_Activation__c
FROM Opportunity
WHERE IsWon = true
  AND CloseDate = THIS_QUARTER
  AND (License_Key_Activation__c = null OR License_Key_Activation__c > THIS_QUARTER_END);

Build it once, run it daily

The crosswalk is worthless as a one-time spreadsheet because the deals move every day. A deal slips, an activation date changes, a multi-year gets restructured to annual, and your reconciliation is stale by lunch. This is rung L4.

So run it against a daily snapshot. Diff today’s opportunity table against yesterday’s, and attribute every change in the gap to a specific deal and a specific field. When the CRM-to-Finance gap moves $80K overnight, you can point at the two opportunities that caused it and the field that changed on each.

Standing up the reconciliation layer
  1. 1

    Trace one real deal through all three systems

    Pull a deal that closed last quarter. Find where Amount, recognized revenue, and the board figure diverge. That single trace surfaces the fields your crosswalk needs and the definition nobody agreed to in writing. This is rung L1.

  2. 2

    Write the field-level crosswalk

    One row per CRM field: its Finance counterpart, the transformation rule, and an owner. The artifact is a table, not a bigger meeting. Rung L2.

  3. 3

    Build the ARR bridge as a query

    Start from SF booked Amount, walk to Finance recognized in named lines. Every adjustment has SOQL behind it and a person who owns it. Rung L3.

  4. 4

    Snapshot the opportunity table daily

    Diff today against yesterday. Attribute every dollar of gap movement to a specific deal and field, so the reconciliation is never stale by lunch. Rung L4.

  5. 5

    Make the board number the bottom of the bridge

    On the last day of the period the board figure is the last row of the recalculated bridge. No hand reconciliation, no hidden tab, no third number. Rung L5.

The daily snapshot also kills the 11pm board-prep scramble. If the bridge recalculates every morning, the board number is the bottom of the bridge on the last day of the period, which is rung L5 holding on its own.

Reconcile by hand at 11pm Field-level crosswalk, daily
Where the gap lives In one person head and a hidden tab In a named, owned bridge query
"Why do the numbers differ?" A shrug and a callback Four lines, each with SOQL behind it
Freshness Stale by lunch the day you build it Recalculated every morning
Overnight gap move Nobody knows what changed Attributed to the exact deal and field
The board sees A single reconciled figure hiding the work The bridge, every dollar traceable
Same $600K gap. One is a scramble that invents a third number; one is a bridge the board can read.

What good looks like

The target is not zero gap. Zero gap means you have forced the CRM to lie about timing or forced Finance to abandon revenue recognition, and both are worse than the gap. The target is an explained gap: every dollar of difference traces to a named rule and a specific set of records.

Healthy looks like this. The CRM number and the Finance number differ by a known amount every quarter, that amount is fully decomposed in the bridge, and the board sees the bridge instead of a single reconciled figure that hides the work. It is worth the build: Ebsta and Pavilion found RevOps-driven teams post 87% higher win rates and 21% shorter cycles (2024 benchmarks), and a revenue number the whole room trusts is the foundation the rest of that operating rigor sits on.

The six rungs of the ladder map onto a parallel question, which is how far to automate. Most teams think they must jump straight to the daily-snapshot version and freeze when they cannot. You do not. The first useful version is a static bridge built by hand once a quarter, worse than the automated one but infinitely better than the 11pm guess because it writes the definitions down.

MaturityWhat existsWhat it buysWhat it still misses
0: the guessOne person, 11pm, hidden tabNothing durableEverything
1: static bridgeHand-built bridge, definitions writtenAnswerable gap, once a quarterStale by lunch, no attribution
2: scheduled queryBridge recalculates on its ownFresh number, no scrambleNo deal-level “what moved”
3: daily snapshotDiff today vs yesterday, per dealAttribute every dollar of movementNothing that matters for the board

The point of the table is permission to start small. A static bridge that names the $600K is a complete win over the status quo, and it is the artifact that makes the case for building the scheduled query and the daily snapshot on top of it. Rungs L2 and L3 of the ladder get you to maturity level 1; L4 gets you to level 3.

Start by pulling one deal that closed last quarter and tracing it through all three systems yourself, which is rung L1 and costs you an afternoon. Find where the Amount, the recognized revenue, and the board figure diverge, and you will almost certainly surface a definition nobody ever agreed to in writing. Once the crosswalk exists, the monthly forecast handshake between RevOps and Finance stops being a fight and becomes a reconciliation, because the two teams are finally arguing about actions instead of about which number is real.

forecasting finance reconciliation

Keep reading

One email. Every week.

One email a week: an operating problem I solved or botched, with the model, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.

The newsletter opens soon.

Connect a provider in src/config.ts