01 — The problemWhy three systems disagree

Each system is right within its own boundaries. CRM tracks contracts. Billing tracks invoices. Operations tracks usage. The trouble is that each system has slightly different definitions of the same entity — different IDs, different start dates, different "active" criteria — and slight differences compound into real-money problems at month-end.

The classic failure mode: a customer signs in CRM with start date Jan 1. Billing only knows about them on the day of the first invoice (Jan 15). Ops sees them when they actually start using the product (Jan 20). At month end, Finance asks "how many active customers did we have in January?" and gets three different answers.

Reconciliation is not a project you finish. It's a control plane you operate.

02 — Step oneCanonical entity resolution

The first job of the reconciliation layer is to map each system's identifiers to a single canonical key. CRM has its own account IDs, billing has its customer IDs, ops has its tenant IDs. Without a canonical key, every join is approximate.

The mapping is usually a small table maintained as the source of truth — sometimes manually, often by joining on stable natural keys (legal name, EIN, primary domain). Once the map exists, every fact in the reconciliation layer references the canonical key, not the source-system key.

canonical_entity_map.sql
CREATE TABLE canonical_entity_map (
  canonical_id    VARCHAR,
  source_system   VARCHAR,    -- 'crm' | 'billing' | 'ops'
  source_id       VARCHAR,
  effective_from  DATE,
  effective_to    DATE,
  notes           VARCHAR,
  PRIMARY KEY (canonical_id, source_system)
);

03 — Step twoDeterministic mismatch rules

Once you can join the systems, you need rules for what counts as a mismatch. These have to be deterministic — no human judgment in the loop — and each rule has to produce a specific, actionable category.

Examples of rules that have earned their keep:

  • CRM_ACTIVE_BILLING_INACTIVE — contract live, no invoice for current period
  • BILLING_ACTIVE_OPS_INACTIVE — invoice issued, no usage in current period (potential refund flag)
  • OPS_ACTIVE_BILLING_INACTIVE — usage detected, no billing record (revenue leakage risk)
  • FTE_THRESHOLD_DRIFT — billed FTEs differ from operational FTE count by more than tolerance

Each rule is implemented as a SQL view or query, and each mismatch row is logged with its rule name, severity, and the canonical IDs involved. Operations then routes each exception to the right team — billing exceptions to AR, contract exceptions to account managers, usage anomalies to product.

04 — OperationalizeDaily snapshots, monthly checkpoints

A reconciliation that runs once a month is too late. By then, the source-of-the-error information has often been lost — invoices have been issued, corrections compound. Run reconciliation daily, store the snapshot, and review the exception list weekly.

The daily snapshot also gives you a drift timeline: you can see when a particular mismatch first appeared, which is half the battle in figuring out the root cause. A mismatch that appeared on Tuesday traces back to a specific change in the source system; a mismatch that's been there for six months is a structural issue.

→ Severity matters

Not every mismatch deserves a ticket. Triage by financial impact: a $500 invoice mismatch is an info-level log; a $50K mismatch is a P1. Severity rules belong in the reconciliation layer, not in human judgment downstream.

05 — TakeawaysBuilding trust through visibility

The goal isn't to eliminate mismatches — those are inherent to having three systems do their jobs. The goal is to make every mismatch visible within 24 hours, categorized, and routed. That's how finance trust gets built.

  • Canonical entity keys are the foundation. Without them, every join is approximate.
  • Make mismatch rules explicit and named. "Something's off" is not a rule.
  • Run daily, review weekly, audit monthly. Drift compounds; cadence catches it early.
  • Severity routes the work. Not every mismatch is an emergency; some are signal worth knowing.

When finance closes the books and the numbers match — quietly, repeatably, without heroics — the reconciliation layer is doing its job.