What one capability unlocks
When you pull records from a CRM, who owns the customer?
Fetching CRM records: sync is easy, source-of-truth is the decision
Pulling a record out of a CRM is one of the friendliest API calls there is. Salesforce and HubSpot both hand you clean, documented endpoints; you authenticate, you ask for a contact, you get a tidy object back. Keeping that object fresh — re-fetching on a schedule, listening for a change webhook — is a little more wiring but no harder in kind. The part that decides whether the integration helps your product or quietly corrupts it isn't the fetch at all. It's a single unglamorous question you have to answer before the first record arrives: when you pull a customer from a CRM, who is canonical?
The question under the call
Every record now exists in two places — the CRM and your product — and the moment that's true, you have to decide which one is allowed to be right. Skip the decision and you haven't avoided it; you've just chosen both, which is the one answer that doesn't work. Two systems that each believe they own the customer don't stay in sync on their own. They diverge, slowly, in directions nobody is watching, until one day a record says X in your app and Y in the CRM and there is no rule anywhere that says which one to trust.
So the question isn't decorative. It's the thing that determines whether the copy you're holding is an asset or a liability.
What the capability gives you
A read into the CRM gives you something genuinely useful: the customer's data where your product can reach it, fast, without a network round-trip on every page load. You can join a contact's company and pipeline stage to the rest of what your product knows and build something neither system could show alone — which is exactly what makes the join worth doing. The CRM stays the place sales lives in all day; your product gets a local, queryable view of the parts it needs. That's the upside, and it's real.
The cost of that upside is the copy. And a copy is only worth holding if you've decided what it's allowed to say.
What you own, and what you leave
Three things are yours to own, and they're all decisions, not code:
- The sync policy — which fields are read-only-from-the-CRM and which are owned locally. A contact's name and company come from the CRM and your product should never overwrite them. But a field your product computes — a usage score, an internal status, a flag only your app understands — is yours, and the CRM has no business setting it. Drawing that line per field, on purpose, is the whole job.
- The conflict-resolution rule — what happens when both sides changed the same field since the last sync. "Last write wins" is the common answer, and it's a perfectly defensible one. But it's a decision, not a default that falls out of the wiring for free. The alternative — the CRM always wins for its fields, your product always wins for its own, and nothing is ever a contested field by design — is often the saner rule, and you only get it by choosing it.
- The sync log — a durable record of what you pulled, when, and what changed. This is the thing that lets you answer "why does this record say X here and Y there" with a row you can read instead of a shrug. When the two systems disagree — and over a long enough window they will — the log is the difference between a five-minute explanation and an afternoon of guessing.
What you leave alone is just as important. The CRM stays the system-of-record for the relationship — the deal history, the notes a salesperson typed, the next-step the account owner set. Do not try to out-CRM the CRM. Your product holds a working copy of the fields it needs, with a clear rule about which way each one flows; it does not try to become the place the sales team lives. The provider does a job your product shouldn't want.
What breaks when it's hacked in
The failure mode has one shape, and it's quiet, which is what makes it dangerous: both systems think they're canonical, so neither defers, and they drift apart with nobody noticing.
It rarely announces itself. An import script writes the customer's email on both sides "to be safe." A well-meaning sync updates a field in both directions because no one decided which way it should flow. Each individual write looks correct. The divergence accumulates underneath — a phone number updated in the CRM but not your copy, a status changed in your app but never pushed back — until a salesperson opens the record, trusts what they see, and acts on a number that was right last month. No error fired. No alert tripped. The data just slowly stopped agreeing with itself, and the first sign of trouble is a customer conversation that goes wrong.
A stale copy that everyone trusts is worse than no copy at all, because no copy at least sends people to the one place that's right.
The inverse of the payment record
It's worth holding this next to its sibling, because they look like opposites and the contrast is the point. The argument for keeping a payment record that's yours and not only the provider's says: don't let an external system be your only source of truth — mirror it locally, because you must be able to answer questions without depending on someone else's uptime.
Here the caution runs the other way. The CRM is the source of truth for the customer relationship, and the risk is the reverse: that you build a second one by accident. The payment note warns against having no local record; this note warns against becoming a rival record. Both are the same underlying discipline — be deliberate about who owns what — pointed at two situations where "just keep a copy" leads to opposite mistakes. With payments, the copy is the safety net. With CRM data, an undisciplined copy is the hazard. Knowing which case you're in is the skill.
Where it shows up in a build idea
This capability almost never ships alone — it's an input to something larger. The clearest example in this set is a campaigner that joins CRM data to email and a schedule: the whole product depends on reading contacts out of the CRM, and the segmentation logic that decides who gets which message is built on top of that read. Get the source-of-truth question right there and the campaign targets people on data you can trust. Get it wrong — let your copy drift — and you're segmenting on stale records, which in an email product means mailing the wrong people for reasons no one can later explain.
That same shape rides on parts a foundation already carries. The scheduled re-fetch is a background job — CompanyGraph runs a batch scheduler in production today, the kind of recurring worker that pulls fresh data on a cadence without blocking anything user-facing. The sync log is logging, and the place an operator goes to ask "what did the last sync change, and when" is the admin — both of which run live underneath CompanyGraph right now. None of that is the part you'd build for a CRM integration; it's the furniture the integration sits on. The new part is the read and, far more importantly, the three ownership decisions around it.
The verdict is the deflating, honest one: fetching CRM records is a capability, not a product, and the engineering is the easy half. The hard half is a governance decision you make once and live with — who is canonical, which fields flow which way, and how you'll know when they disagree. Make that call deliberately and a CRM read is a quiet asset. Make it by default and you've built a second source of truth that lies to you slowly.
The background jobs, logging, and admin that make a sync trustworthy are part of the foundation that already runs under CompanyGraph — so the new work is the ownership decision, not the plumbing. If you've got an idea that joins a CRM to something, the next sensible step is to put the source-of-truth question on the table before the first record syncs.
Articles describe the Foundation. The Foundation Map is the thing itself — accounts, admin, email, logging, and deployment, with one real workflow running through them.