Skip to main content
BlogSeptember 30, 202611 min read

Bi-directional sync for finance data: how to avoid overwrites, and real-time vs batch

Two-way syncs overwrite each other without a system of record for each field. How to set ownership rules and choose real-time or batch for CRM-to-ERP data.

Zuny FesterBy Zuny Fester, Head of Operations and Marketing
Reviewed by Zuny Fester
Published Editorial policy

Part of the payment reconciliation and cash application guide.

Bi-directional sync for finance data: how to avoid overwrites, and real-time vs batch

Bi-directional syncs avoid overwriting each other's data by giving every field exactly one system of record and syncing it in one direction only. "Two-way sync" should mean two one-way flows over different fields, not two systems allowed to edit the same field. Add origin tagging so a sync never re-processes its own writes, and pick a cadence per field: near real-time for fields that block a customer-facing action, batch for everything else.

Most overwrite problems between a CRM and an ERP aren't bugs in the connector. They're an ownership decision nobody made. This guide gives you the field-ownership table that makes that decision explicit, the loop-prevention rules, and a way to choose real-time or batch per field.

Key takeaways

• One field, one owner. Every synced field has a single system of record; the other system gets a read-only copy.

• Two-way sync is two one-way flows. Customer name flows CRM → ERP; invoice status flows ERP → CRM. Neither system writes the other's fields.

• Tag the origin of every write. Salesforce Change Data Capture exposes a changeOrigin header specifically so an app can detect its own changes and avoid a cycle of updates.

• "Last write wins" is not a finance control. It hides conflicts instead of surfacing them; conflicts on owned fields should go to a person.

• Choose cadence per field, not per integration. Credit hold and invoice status often justify near real-time; price books and AR balances usually don't.

• Loopfour, the deterministic finance workflow automation platform, runs CRM-to-ERP sync on a field-ownership model with predefined direction and cadence, and holds conflicts for approval.

Why do bi-directional syncs overwrite each other?

Bi-directional syncs overwrite each other when both systems are allowed to edit the same field and the sync resolves the conflict by timestamp. Sales updates a billing address in the CRM. AR updates the same address in the ERP after a customer call. The next sync copies whichever changed last, and the other edit disappears.

Three patterns cause most overwrites:

PatternWhat happensSymptom
Shared ownershipBoth systems can edit a field; the latest timestamp winsEdits vanish; nobody knows which value is right
Echo loopThe sync writes to System B, B's change event triggers a write back to ARecords update repeatedly; API limits hit; audit logs flood
Stale batchA batch job copies a snapshot taken before a newer editOld value overwrites a newer one on the next run

All three disappear when each field has one owner and one direction. The echo loop also needs origin tagging, covered below.

The field-ownership table

The field-ownership table is the design document for any two-way sync: field → system of record → direction → cadence → conflict rule. Build it before configuring any connector. Here is a working version for a Salesforce and NetSuite setup; the same structure fits HubSpot, Attio, QuickBooks, or Sage Intacct.

FieldSystem of recordDirectionCadenceConflict rule
Master customer IDCRM (minted at account creation)CRM → ERP, write onceOn creationNever overwritten; mismatch is an exception
Customer legal nameCRMCRM → ERPNear real-time on changeERP edits blocked or flagged
Billing address and billing contactERP (AR team)ERP → CRMHourlyCRM field read-only
Subsidiary and currencyERPERP → CRMOn creation, then dailyChange requires approval
Payment termsERPERP → CRMDailyCRM field read-only
Credit hold statusERPERP → CRMNear real-timeCRM field read-only
Opportunity amount, close date, productsCRMCRM → ERP, once, at closed-wonOn closed-wonPost-sync edits go through change order, not sync
Sales order and invoiceERPERP → CRM (status only)Near real-time or hourlyCRM never edits
Invoice status and amount paidERPERP → CRMHourlyCRM never edits
Open AR balanceERPERP → CRMDailyCRM never edits
Item and price bookERPERP → CRMDailyCRM price changes go through approval
Account owner (sales rep)CRMCRM → ERPDailyFeeds commissions; ERP read-only

Read the table by column, not by row. The Direction column shows that the "two-way sync" is really a set of one-way flows. The Conflict rule column shows that no field is resolved by timestamp. If a field needs to be edited in both places, that's a process problem to solve with a request workflow, not a sync setting.

Invoice status back to the CRM is often the first flow teams want. The specifics for NetSuite and Salesforce are in how to sync invoice and payment status from NetSuite back to Salesforce. If your systems don't share a customer key yet, fix that before anything else, using the approach in how to map fields between finance systems that don't share an identifier.

How to stop sync loops

Stop sync loops by tagging every write with its origin and discarding change events your own integration caused. Without this, a write to System B fires a change event, which the sync reads as a new change and writes back to System A.

Both major platforms give you what you need:

• Salesforce. Change Data Capture events carry a header with changeOrigin, changedFields, and commitTimestamp. Salesforce's ChangeEventHeader documentation says changeOrigin lets you detect whether your app initiated the change, so you don't process it again and avoid a deep cycle of changes. changedFields tells you which fields moved, so a sync only acts when an owned field changed.

• NetSuite. SuiteScript can read runtime.executionContext to tell a user interface edit from a web services, REST, or CSV import change. A user event script can skip outbound sync when the change came from the integration itself.

Add one more guard: compare before you write. If the target already holds the incoming value, skip the write. That single check removes much of the echo traffic even when origin tagging is imperfect.

The loop-safe flow:

Change event → read origin → discard if integration-originated → check changed fields against ownership table → compare to target value → write only owned fields that differ → log.

How often should CRM-to-ERP finance data sync: real-time or batch?

Sync in near real-time only when a stale value blocks an action or creates risk within minutes; sync everything else in batch. Real-time costs more in API calls, error handling, and monitoring. Batch is simpler to reconcile. Choose per field.

QuestionIf yesExample fields
Does a stale value let someone take a wrong customer-facing action?Near real-timeCredit hold, invoice paid status before a collections call
Does a downstream process start from this change?Event-drivenClosed-won creating a sales order
Is the value used for reporting or planning only?Daily batchAR balance, lifetime revenue
Does the value change rarely and centrally?Daily or on changePrice books, payment terms
Does the source post in batches anyway?Match the source cadencePayments applied in a nightly cash application run

A useful test: if a sales rep or collector saw the old value, would they do something wrong in the next hour? If yes, near real-time. If no, batch, and put the last-synced timestamp on the record so users know how fresh it is.

Batch also has a control advantage: a batch run is a natural unit for reconciliation. You can count records in, records written, and exceptions, and compare. Event-driven syncs need the same counts, rolled up by hour or day, or silent gaps go unnoticed.

Book a workflow review to see your own CRM-to-ERP fields mapped into an ownership table with direction and cadence set per field.

What about conflicts that still happen?

Route them to a person, with both values and both timestamps, and record the decision. Even with clean ownership, conflicts arise: someone edits a read-only field through an admin permission, a data import bypasses the rules, or two records merge.

• Detect. Before writing, compare the target's current value to the last value the sync wrote. If they differ, someone changed the target outside the sync.

• Hold. Don't overwrite. Create an exception with the source value, the target value, who changed each, and when.

• Decide. A named owner picks the correct value in Slack, and the sync applies it.

• Record. The decision and the approver go into the run's log.

That is slower than last-write-wins by design. For finance fields, a visible conflict is cheaper than an invisible overwrite discovered at audit.

How to choose a tool for bi-directional finance sync

Choose a tool that lets you encode field ownership, direction, cadence, and conflict rules explicitly, and that shows you what it did on every run. Most integration platforms can move fields both ways. The difference is whether they make you decide ownership or let you skip it.

Horizontal iPaaS tools and packaged connectors are flexible and fast to deploy, and for teams with integration engineers they're a strong option; we compare three of them in Celigo vs Boomi vs Workato for NetSuite-Salesforce finance sync. Their default conflict behavior is often timestamp-based, and changing that is your build to maintain.

Loopfour takes a narrower position. The field-ownership table is the configuration: each field's owner, direction, and cadence are set in advance, integration-originated changes are discarded, and conflicts stop and ask a named approver. We build it on your existing Salesforce, HubSpot, NetSuite, QuickBooks, or Sage Intacct accounts and maintain it when either side changes. Every run leaves an execution tree showing which fields moved, in which direction, and who resolved each conflict.

Frequently asked questions

How do bi-directional syncs avoid overwriting each other's data? They assign each field a single system of record and sync it in one direction only, so both systems never edit the same field. They also tag writes by origin to ignore their own changes, and route any true conflict to a person instead of resolving it by timestamp.

How often should CRM-to-ERP finance data sync? Sync fields in near real-time when a stale value would cause a wrong action within the hour, such as credit hold or invoice paid status. Sync reporting fields such as AR balances, price books, and payment terms in daily batches, and show users the last-synced time.

What is a field-ownership table? A field-ownership table lists every synced field with its system of record, sync direction, cadence, and conflict rule. It's the design document for a two-way integration and should be agreed by finance, sales operations, and whoever maintains the sync.

Is last-write-wins acceptable for finance data? Not for fields that affect invoicing, revenue, or collections. Last-write-wins silently discards one edit; for finance data, conflicts should be held and resolved by a named owner with the decision logged.

How do I stop an infinite sync loop between Salesforce and NetSuite? Discard change events your integration caused, using Salesforce's changeOrigin header and NetSuite's execution context. Also compare the incoming value to the target before writing, and skip the write if nothing changed.

Should the CRM or the ERP own the customer record? Usually the CRM creates the customer and owns sales-facing fields such as name and account owner, while the ERP owns billing address, subsidiary, payment terms, and credit status. Whatever split you choose, write it down per field.

Conclusion

Bi-directional sync for finance data works when each field has one owner, one direction, and a cadence that matches how the value is used. Tag origins to stop loops, compare before writing, and send real conflicts to a person. Build the field-ownership table first, and the connector becomes a much smaller decision.

Tell us the one workflow your team dreads. We will show it running — deterministic, permissioned, and auditable.

Book a demo.

Sources

• Salesforce: ChangeEventHeader fields (Change Data Capture)

• Oracle NetSuite: runtime.executionContext

• How to sync invoice and payment status from NetSuite back to Salesforce

• How to map fields between finance systems that don't share an identifier

• Celigo vs Boomi vs Workato for NetSuite-Salesforce finance sync

• How to integrate NetSuite with Salesforce for finance teams

• Salesforce-to-NetSuite sync errors: invalid subsidiary references and missing price books

Sources

  1. Salesforce, Change Data Capture Event Fields: Header (opens in a new tab).
  2. Oracle NetSuite, NetSuite Help Center (opens in a new tab).