Support

Need help?

Most answers are already written down. For everything else, Oneop does not publish a response time — there is no SLA instrument behind one — so the fastest thing you can do is send a complete first message.

Search the help centreEmail support@oneop.ioOpen your workspace

Worth including

  • The email you log in with
  • The URL of the screen it happened on
  • What you expected, and what happened instead

Goes somewhere else

Architecture

Connecting CRM, invoicing and accounting without reconciliation chaos

By The Oneop team7 min read

TL;DR

CRM and accounting systems diverge because each keeps its own copy of the same five things: the contact, the product, the price, the tax treatment and the payment status. A scheduled sync cannot prevent divergence, it can only shorten it, because every sync window is a period in which two systems hold different answers.

Nobody sets out to build a reconciliation process. It arrives as a side effect of three sensible purchases: a CRM for the sales team, an invoicing tool for the finance team, and an accounting package for the books. Each is good at its job. The work that appears afterwards is the work of keeping three copies of the same business in agreement, and it is unbounded, because it scales with transaction volume rather than with company size.

This post is about where the copies actually diverge, why a sync schedule cannot close the gap, and what specifically disappears when the record is shared instead of copied.

Five things every system keeps its own copy of

Integration diagrams are drawn as arrows between boxes. The failures are not in the arrows, they are in the duplicated fields. Five duplicates cause nearly all of the pain.

EntityCopy in the CRMCopy in invoicing or accountingHow the divergence shows up
Contact and billing addressAccount record, edited by salesCustomer record, edited by financeInvoice sent to an address changed three weeks ago
Product or SKUCatalogue item on the dealItem on the invoice lineA renamed or retired SKU invoices under the old description
Price and discountNegotiated on the quoteRate on the invoice lineInvoice bills list price after an approved discount
Tax treatmentOften absent entirelyDetermined at invoice timeExempt customers taxed, or taxable customers not
Payment statusRead to decide whether to chaseWritten when cash is appliedA paid customer receives a dunning email

Note the direction of each one. Contact, product and price flow from the commercial side toward finance. Tax is usually determined only in finance. Payment status flows the other way, from finance back to the people talking to the customer. A sync that is reliable in one direction and best-effort in the other still breaks, and it breaks on the leg nobody tested.

The failure, in one afternoon

Here is the concrete case. A customer pays an invoice by bank transfer on Thursday morning. The finance system applies the payment at 11:20 and marks the invoice settled.

The CRM holds its own payment_status field, refreshed by a sync that runs nightly at 02:00. At 14:00 on Thursday, an automated dunning sequence reads the CRM copy, sees unpaid, and emails the customer a reminder with a late-payment warning. The customer forwards the reminder to their accounts payable team, who confirm the transfer, and someone on your side spends twenty minutes proving the payment was received.

Nothing malfunctioned. The sync ran on schedule. The dunning automation read the field it was designed to read. The finance system recorded the payment correctly. Every component behaved exactly as specified, and the customer still got a wrong email, because for fifteen hours the business held two different answers to the question “has this invoice been paid” and the automation happened to ask the stale one.

You cannot test this away. The only variable is the length of the window, and any window longer than zero eventually contains an event that cares.

Why nightly sync produces drift rather than delay

A scheduled sync is usually described as latency: the data is correct, just late. That description is too generous. Four mechanisms turn latency into permanent divergence.

Conflicting edits. Both sides change the same field inside one window. The sync applies a conflict rule, usually last-write-wins by timestamp, and one edit is destroyed. Nobody is told which.

Partial failure. A sync run pushes 400 of 500 records and then hits a validation error on record 401. The first 400 are committed. The remaining 99 are not attempted. There is no transaction spanning the two systems, so there is no rollback, and the next run starts from a state that is neither the old one nor the new one.

Silent schema mismatch. A field added on one side has nowhere to land on the other. The sync maps what it knows and drops the rest without error, because dropping unmapped fields is normal behaviour.

Replay and duplication. A webhook redelivered after a timeout creates a second payment record unless every consumer is idempotent. Idempotency is easy to specify and easy to forget on the fourth integration.

Each mechanism produces a difference that the next sync does not correct, because the next sync has no memory of what the correct value was. That is the definition of drift: divergence that persists after the mechanism meant to fix it has run.

What a shared record actually removes

The alternative is not a faster sync. It is not having a second copy to synchronise.

When a deal, its invoice, the stock movement it triggered and the journal entry it posted are rows in one database, a set of questions stops existing:

  • Which system owns the customer’s billing address? There is one address row.
  • What happens if the invoice writes but the ledger entry fails? They are one transaction, so both happen or neither does.
  • How do we handle a conflicting edit? Two edits to one row serialise at the database, as they would anywhere else.
  • How long until the CRM knows the invoice was paid? It already knows, because it is reading the same row finance wrote.

This is not a claim that unified software is better at everything. It is a narrower and more defensible claim: the reconciliation class of failure is caused by duplication, and removing the duplicate removes the class. The same reasoning underlies why an AI agent needs a system of record rather than a context window. An agent reading a stale copy makes confident, wrong decisions faster than a person does.

Where an integration is still the right shape

Draw the boundary honestly. External systems with their own authority over their own data should be integrated, not absorbed: payment processors, bank feeds, carriers, marketplaces, tax authorities. Their data is genuinely theirs, the direction of truth is clear, and you have no ability to unify anyway.

What benefits from unification is the internal boundary between your customer, your order, your invoice and your ledger. That boundary usually exists for procurement reasons rather than architectural ones, which is why it is worth removing and why removing it feels disproportionately effective.

There is also a useful middle pattern for the external cases. Oneop’s bank reconciliation keeps the bank line and the posted ledger line as two rows joined by a match score rather than merging them into one record, and a person confirms, unmatches or excludes each match before the reconciliation is finalised. Two rows are correct there, because the bank’s record and yours are genuinely different assertions that should be compared rather than assumed equal.

How Oneop is built for this

Oneop runs on one PostgreSQL database with one tenant boundary: 329 tables, of which 275 carry a tenant_id. A deal in the CRM, the invoice it became in finance and the stock movement it triggered are rows in that one database, not records synced between separate services.

The mechanical proof is the reverse direction. Voiding an invoice reverses its ledger entry and releases the stock it had reserved, in the same action, because both live in the same transaction boundary. No integration is capable of that guarantee, and no integration should be blamed for not providing it.

External connections still exist and are listed on the integrations directory, where they belong: processors, stores, carriers and accounting exports that genuinely live outside your workspace. The distinction the architecture makes is which boundaries are real.

For the currency-specific version of the divergence problem, where two systems hold two exchange rates for the same invoice, see multi-currency accounting. For the document-level version, where the invoice quantity and the shipped quantity come from two different processes, see invoicing from what shipped.

Frequently asked questions

Why do CRM and accounting systems drift out of agreement?

Because each one stores its own copy of the same entities and each one accepts edits to that copy. A contact updated in the CRM and a contact updated in the accounting system are two independent writes to two rows. A sync reconciles them later, which means there is always a window in which both are live and different, and a conflict rule has to decide which edit survives.

Can a real-time integration prevent reconciliation work?

It reduces the window but does not remove the class of failure. A real-time integration still involves two systems, two writes and a network in between, so it still has to define what happens when the second write fails, when both sides are edited at once, and when a webhook is delivered twice. Those are the conditions that produce the drift, and shortening the window makes them rarer rather than impossible.

What is the hardest field to keep in sync between CRM and accounting?

Payment status, because it changes in the accounting system and is acted on in the CRM. A payment is recorded against an invoice in finance; the sales and support side reads paid or unpaid to decide whether to chase, to release an order, or to escalate. Any lag in that direction produces visible, customer-facing mistakes such as dunning a customer who paid yesterday.

Is a single database the only way to avoid reconciliation chaos?

It is the only way to remove the problem structurally, but it is not always available or worth the migration. Where separate systems are a given, the realistic mitigation is to designate exactly one writer per field, make every other system read-only for that field, and log every sync outcome so a failed write is visible rather than silent. That is discipline substituting for architecture, and it degrades under staff turnover.

What should be integrated rather than unified?

Systems you do not control and do not need to write to, such as a payment processor, a bank feed, a carrier or a marketplace. Those are genuine external boundaries with their own authority over their own data, and an integration is the correct shape. The boundary worth removing is the internal one between your own customer, order, invoice and ledger records, which has no reason to exist except that the software was bought separately.

Written by

The Oneop team

Writing from the team that builds Oneop — an AI customer platform with web chat and email on top of a real CRM, help desk, ledger and warehouse.

Related reading

Start on the free plan and see the real thing

No credit card. Free plan, 2 seats.

Free forever · 2 seats · No credit card