The setup
Each connection was added for a good reason, at a different time, by a different team. Marketing wanted lead data flowing into the CRM. Finance wanted CRM account data flowing into the ERP for billing. Sales wanted ERP order history visible back in the CRM. Three separate initiatives, three separate consultants, three separate sync tools — an iPaaS connector here, a native integration there, a scheduled script running on someone's laptop cron job for the third.
Nobody sat down and mapped the full loop until it was already a triangle: CRM to MAP, MAP to CRM, CRM to ERP, ERP to CRM. Every system was both a source and a destination for contact and account data, and none of the three connectors were aware the other two existed.
The collapse
It started small: a contact created in the MAP from a webinar signup synced to the CRM. A sales rep manually created what looked like a new contact in the CRM the same afternoon, because the sync had a few hours of lag and the rep didn't see the first one yet. Now there were two. The ERP connector, matching on name and company rather than a stable ID, pulled both into billing as separate records. Then the CRM-to-MAP sync mirrored the ERP's version of "two contacts" back into marketing.
Multiply that by normal day-to-day usage across 250 employees for over a year, and the matching logic — which used fuzzy name/email matching instead of a persistent cross-system ID — kept finding new near-duplicates and creating fresh copies rather than merging them. Contact counts grew roughly 4x over baseline. Email deliverability dropped as the same person got multiple sequences from different "versions" of themselves. And because personal data was flowing through three systems with no consistent record of consent source, a data subject access request surfaced that nobody could answer cleanly — a name existed in six different states across the three platforms, with six different timestamps and no clear lineage of which was authoritative.
By the time it reached RevOps as an official problem, "clean up the duplicates" wasn't a weekend project. It was a multi-quarter deduplication and re-architecture effort, done while the sync loop was still live and still creating new duplicates daily.
The autopsy
Root causes on record
- No single source of truth was ever declared. Three systems, all writable, all syncing — with no rule for which one wins a conflict.
- Matching on name/email instead of a stable ID. Fuzzy matching creates near-duplicates under normal business usage, it doesn't just fail on edge cases.
- Each integration was scoped by the team that needed it, in isolation. Nobody owned the full data-flow diagram until it was already a loop.
- No monitoring on sync volume or duplicate rate. A 4x contact count increase should trip an alert long before a DSAR forces the question.
- Consent and data-source lineage weren't tracked per record. When compliance asked "where did this person's data come from and who can update it," there was no clean answer.
Recommendation pending
Editor's note: this slot will point to an integration/iPaaS platform built around a declared source-of-truth and durable ID matching — the thing that would have kept this from becoming a loop in the first place.
What the post-mortem actually changed
RevOps forced a "single writable system per field" policy: the CRM owns contact identity, the ERP is read-only for contact data and only writes order history, and the MAP only writes engagement data, never core fields. Every sync now matches on a persistent cross-system ID generated at first contact creation, not name or email. It's less flexible than what any one team originally wanted. It's also the only version that stopped generating new duplicates.