Write the ownership map before anyone writes a connector
The deliverable that saves the most money in a CRM integration is a single page nobody bills for: a table of every field that will cross a boundary, with one system named as its owner. Not two. One. Who owns the customer's legal name? Their billing address? Their shipping address, which is often different and often plural? Credit terms? The product list? Price? Contract end date? Support tier? For each, exactly one system is allowed to change it, and everywhere else it is a copy that is displayed and never edited.

This sounds like an afternoon of paperwork and it is. It is also the difference between an integration that runs for five years and one that produces a standing argument between sales and finance about whose address is right. The argument is not really about addresses. It is about the fact that both systems allow the field to be edited and neither one was ever declared the source.
The map surfaces real disagreements immediately, which is the point. A distributor doing this found that sales had been changing payment terms in the CRM for two years, that those changes never reached the order system, and that at least four customers believed they had terms nobody in accounting had ever heard of. That is not an integration finding. It is an operational finding that the integration was about to make either much better or much worse.
You are probably here because
- Reps type the same customer into two systems and have stopped bothering with one
- Finance and sales quote different numbers in the same meeting, from the same customer
- An integration built two years ago has been failing quietly and nobody can say since when
- You just acquired a company and now there are two CRMs and two billing systems
The first two are ownership problems. The third is a monitoring problem. The fourth is an identity problem, and it is the most expensive of the three.
Account identity is the actual project
Your CRM has “Acme Corp,” “ACME Corporation,” “Acme Corp – Northeast” and “acme corp (do not use).” Your order system has customer numbers 40122 and 40877, which are the same company billed to two addresses because that is how the credit department set them up in 2019. Your support desk keys off email domain, which breaks for the customer whose people use three domains after their own acquisition.
Matching these is the work. Nothing else in the project can be correct until it is, because every synchronized record has to land on the right account, and “the right account” does not exist yet as a concept both systems agree on.
The practical approach is unglamorous and it works. Choose one system to hold the durable identifier — usually the billing or order system, because that identifier already appears on documents and in the ledger and cannot be casually changed. Add a field on the CRM account to hold it. Then match: exact matches on tax identifier or account number first, then normalized-name plus address matching, then a human reviewing what is left. Expect the human queue to be larger than anyone estimated; a few thousand accounts routinely produce several hundred that need eyes.
Then close the door behind you. New accounts created in the CRM must acquire the identifier through a defined step — either the CRM creates the record in the order system through the integration, or a person completes the link before the account can progress. If a rep can create an unlinked account and move it through a pipeline, you will be redoing the matching exercise within a year.
Direction: one-way is usually the right answer
Two-way synchronization is the default request and it is right perhaps a quarter of the time. It roughly triples the cost, because it introduces the two problems that generate almost all long-run integration pain: conflicts and loops.
A conflict is when the same field changed on both sides between syncs. The usual policy is last-write-wins, which is a polite name for silent data loss — the earlier edit vanishes with no record that it existed. Sometimes that is acceptable. It is never acceptable for a field somebody will be held to, like credit terms or a contract date. For those, the correct behavior is to refuse the update and raise it to a person, which means building a queue and giving someone the job of clearing it.
A loop is when system A writes to B, which fires a change event, which writes back to A, which fires another. This is not hypothetical; it is the standard failure of a first two-way build, and it usually announces itself by consuming an entire day's API allocation in twenty minutes. The defenses are simple once you know to build them: mark integration-originated writes and ignore them as triggers, and compare values before writing so a write that changes nothing is not performed.
Before agreeing to bidirectional sync, ask the question that usually settles it: does anyone actually edit this field on the far side? Very often the answer is no, they just want to see it, and a read-only display of the authoritative value is a fifth of the work and cannot go wrong.
| Pattern | Fits when | What it costs |
|---|---|---|
| One-way, source to copy | The far side displays but never edits | Least. Start here and stay if you can |
| One-way per field, both directions | Each field has one clear owner, owners differ | Moderate. No conflicts by construction |
| True bidirectional on a field | Both sides genuinely author it | High. Needs conflict policy, a queue, loop guards |
| Warehouse in the middle | Many systems, batch tolerable, analytics wanted | Moderate infrastructure, poor latency for live lookups |
| Live read-through, no copy | The far system is fast and always available | Low storage, but you inherit its downtime |
API budgets are a design constraint, not a footnote
Every major CRM meters access. The specifics differ by platform and by what you are licensed for, but the shape is the same: a bounded number of calls in a rolling window, limits on how much can be pulled at once, and separate quotas for bulk operations. Exceed them and the platform stops answering — for your integration and, on some platforms, for other things your business depends on.
Two habits keep you inside the budget. Sync deltas, not everything: ask for records modified since the last successful run, not the full table. And batch: sending records in bulk rather than one call per record is often an order-of-magnitude difference in consumption. A nightly full pull of a few hundred thousand contacts, one call at a time, is the classic way a first integration exhausts a daily allocation before the sales team logs in.
Do the arithmetic before you design. Record counts, expected daily change volume, calls per record under your chosen pattern, and the published quota for your tier. If the numbers do not fit, the architecture has to change, and it is far cheaper to learn that on a page than in production at nine in the morning.
Where a CRM integration actually consumes effort — our split
Percent of effort on a first multi-system integration. Our judgment, not a measurement. The last row is what the vendor demo shows you.
Every job must be safe to run twice
Sync jobs fail partway. Networks drop, tokens expire, the far system has an outage at 3 a.m., someone deploys. The only sane response is to re-run, and re-running is only safe if the job is idempotent — running it twice produces the same result as running it once.
In practice that means every record written carries a stable external identifier from the source system, and writes are performed as upserts keyed on it rather than as blind creates. Without that, a retried job creates a second copy of every record it already wrote, and you find out when a rep opens an account and sees the same contact three times.
Two companions to that rule. Keep a watermark of the last successfully processed change per object, updated only after the batch is confirmed, so a failure resumes rather than restarts. And log every write with enough detail to answer “why does this field say that?” six months later — source, timestamp, prior value, job identifier. That log is the first thing anyone reaches for during a dispute and it is almost never built until after the first dispute.
Merges and deletes, the case nobody handles
Someone in sales will notice two records for the same company and merge them. This is correct behavior and the CRM makes it easy. Downstream, the losing record's identifier now points at nothing, and every system holding a reference to it is quietly broken. Opportunities, tickets, invoices, marketing history — all pointing at a ghost.
Handle it explicitly. Subscribe to merge events where the platform emits them, keep a table mapping retired identifiers to their survivor, and resolve through that table on every lookup rather than assuming an identifier is permanent. The same table saves you when a record is deleted, which is the other thing that will happen: decide whether a delete on one side means delete, deactivate, or nothing at all on the other, and write that decision down. The default of propagating deletes is almost always wrong for anything with financial history attached.
Custom fields are a governance problem wearing a technical costume
A CRM that has been in use for five years typically has several hundred custom fields, and a large share of them are filled in on under five percent of records. Before integrating, run the fill rates and hold one meeting to retire the dead ones. Every field you carry across a boundary is a mapping to maintain, a migration to test, and a thing that breaks when someone changes a picklist value. The cheapest integration work is the field you agreed not to sync.
The failure mode is silence
Integrations rarely fail loudly. A token expires, a required field gets added on one side, a picklist value changes, and the job starts erroring on a subset of records while succeeding on the rest. Nobody notices, because nothing looks broken from a user's chair — the data is just slightly older every day.
The most common finding when we are asked to look at an existing integration is that it has been partially failing for weeks and nobody could say since when. The fix is cheap and almost never present. Alert on the absence of a successful run, not only on errors, because a job that stopped being scheduled produces no errors at all. Publish a simple dashboard with last successful run time and record counts per direction. And run a nightly reconciliation that counts records on both sides and reports the difference, because counts diverging is the earliest honest signal that something has gone wrong.
Send us your field list and we will send back the ownership map.
An export of the fields on your account and contact objects, the systems involved, and roughly how many accounts you have. Email contact@precisionfederal.com and you get a written first-pass ownership map, the fields we would refuse to sync, and where we expect the account matching to hurt. One business day, no charge.
contact@precisionfederal.comThe backfill is a separate project
Ongoing sync and initial load are different problems and teams that treat them as one lose a week. The ongoing job handles tens or hundreds of changes an hour. The backfill handles every record you have ever had, hits every rate limit at once, and runs into all the historical data that violates rules the current system enforces — accounts with no owner, contacts with no email, records created before a required field existed.
Plan it separately, with its own throttle, its own resumability and its own report. Decide how far back you actually want to go; the answer is often far less than everything, and every year of history you skip removes a category of exception. And run it once against a copy first, because the backfill is where you discover that four percent of your accounts fail validation for reasons that pre-date everyone in the room.
Adoption is the reason to do this at all
The business case usually gets written as efficiency, and the real return is that people start using the CRM. Reps do not stop updating records because they are undisciplined. They stop because the same information has to be typed in two places and one of them is not the one that pays them. Every field the integration fills automatically is a field a rep does not skip.
Which is a useful design filter. Rank candidate integrations by how much duplicate typing they remove for the people you most need in the system. An order-status field that appears on the account, so a rep can answer a customer without opening the order system, is worth more than three fields that only a report consumes. Ask the reps which screen they keep open in a second tab; that tab is your integration backlog, in priority order.
What it costs and how long it takes
For a first real integration — CRM to an order or billing system, with account matching, a field ownership map, one-way sync in each direction, a backfill, monitoring and a repair queue — plan on roughly six to twelve weeks and a build cost in the mid-five to low-six figures. Account matching is the variable that moves it most; a clean account list at the low end, a messy one after an acquisition at the high end.
Each additional system afterward is faster, but not half. The plumbing and the identity work carry over; the field semantics and business rules do not, and those are most of the effort. Three to six weeks per additional system is a reasonable planning figure.
Then budget maintenance honestly at something like ten to twenty percent of build cost per year. That is not padding. Every connected vendor ships API changes, deprecates versions, adjusts limits and alters object models on their own schedule, and each one is a small piece of work that arrives with a deadline you did not choose. An integration nobody maintains is an integration that will be silently wrong within eighteen months.
When you do not need software for this
Some flows genuinely do not justify a connector. If finance needs a list of closed deals once a week and the volume is forty rows, a scheduled export into a shared folder is fine, and it will still be working in five years with no maintenance. If two systems each hold data the other never edits and nobody needs it live, a nightly file is a legitimate architecture rather than a failure of ambition. Reserve real integration for flows where staleness has a cost you can name, and let the rest be a report.
The mistakes we get called in to fix
- No ownership map, so two systems both allow editing and neither is right
- Bidirectional sync by default, with last-write-wins quietly discarding edits
- Account matching skipped, leaving records attached to the wrong customer
- Non-idempotent jobs, so a retry duplicates every record it already wrote
- Full pulls, one call per record, exhausting the daily API allocation by mid-morning
- No handling for merges, so downstream references point at retired identifiers
- Alerting only on errors, so a job that stopped running raised nothing for eleven days
- Four hundred custom fields mapped because nobody would decide which ones were dead
Before you approve the build
- A field-level ownership map exists and both business owners signed it
- One system holds the durable customer identifier, and the CRM stores it
- Account matching is done, with a human queue for the remainder
- New accounts cannot progress without a linked identifier
- Every field is one-way unless someone can name who edits it on both sides
- API call arithmetic done against your actual quota and record counts
- Every job is idempotent, keyed on a stable external identifier
- Merge and delete behavior is written down per object
- Alerts fire on a missing successful run, not only on errors
- Backfill planned and rehearsed separately from the ongoing sync
Bottom line
CRM integration looks like a connector problem and is actually an agreement problem. Decide who owns each field, agree on what a customer is, and prefer one direction over two wherever anyone will let you. The engineering that keeps it alive afterward is unfashionable: idempotent jobs, resumable watermarks, a merge map, a reconciliation count, and an alert that fires when nothing happened. Get those and the integration disappears into the background, which is exactly where it belongs.
Frequently asked questions
Usually not. Two-way sync roughly triples cost because it introduces conflicts and loops, and it is only warranted where both sides genuinely author the same field. Ask whether anyone actually edits the field on the far side; very often people only want to see it, and a read-only display of the authoritative value is a fraction of the work with no way to go wrong.
Pick one system to hold the durable identifier — usually billing or orders, since that number already appears on documents. Store it on the CRM account. Match in layers: exact identifiers first, then normalized name plus address, then a human queue for the rest. Expect that queue to be bigger than estimated, and close the door afterward so new accounts cannot progress unlinked.
A platform is a good fit for common object-to-object flows between well-supported systems, and it removes real plumbing work. It helps much less with the parts that dominate the effort — account matching, field ownership, business rules, backfill. For a handful of flows with heavy business logic, a small set of well-monitored custom jobs is often simpler and cheaper to keep alive.
Alert on the absence of a successful run, not only on errors, because a job that stopped being scheduled produces no errors. Publish last-successful-run time and per-direction record counts where somebody sees them. Then run a nightly reconciliation that counts records on both sides — a diverging count is the earliest honest signal that something has broken.
For a first integration with account matching, an ownership map, one-way sync in each direction, backfill and monitoring, plan on six to twelve weeks and a build cost in the mid-five to low-six figures, driven mostly by how messy the account list is. Each additional system is typically three to six weeks. Budget ten to twenty percent of build cost annually for maintenance, because every connected vendor changes their interface on their own schedule.
