Skip to content
Solutions Blueprint

Deduplicating Company Records From a Practice-Management CRM

Hero featured image

Company records synced from Xero Practice Manager kept re-creating themselves in HubSpot. HubSpot's native Company deduplication checks for a domain or a website, and most of the records XPM was feeding it had neither: trusts, self-managed super fund trustees, and single-purpose companies with no web presence to key on. The rebuild replaced name-based matching with XPM's own Client Export Code, a unique identifier already stamped on every exported record, and re-keyed the sync to match on it instead.

Executive Summary

context-header-icon

Context

The client is a multi-division professional-services advisory group whose accounting and tax practice ran its client and job records through Xero Practice Manager, one of several practice-management systems feeding a new HubSpot CRM. Most of its client entities were structured as trusts, SMSFs, or single-purpose companies rather than ordinary trading businesses, so the signals HubSpot uses to tell one Company record from another were never populated.

what-we-built-header-icon

What We Built

We rebuilt the XPM-to-HubSpot Company sync around XPM's Client Export Code, replacing the name-matching logic that had been quietly duplicating trust and SMSF records since the integration went live, and re-keyed the Jobs-to-Company association to run against the same identifier.

tech-stack-header-icon

Tech Stack

  • HubSpot Sales Hub, HubSpot Operations Hub, Xero Practice Manager (XPM), Client Export Code match

Not a fit if your CRM companies are ordinary trading businesses that already carry a domain and a website. HubSpot's native deduplication handles that case on its own, and a custom identifier match adds a system to maintain that a client in that position doesn't need. This build only pays off when a real share of your accounts are trusts, SMSFs, or other entities with no web presence for HubSpot's own matching to key on.

the-challenge-header-icon

The Challenge

Client and job records flowed out of Xero Practice Manager into HubSpot Companies, one entity at a time: trusts, SMSF trustees, holding companies, and single-purpose Pty Ltd companies set up around individual client structures. HubSpot's own deduplication needs a domain or a website to tell two Company records apart, and most of these entities didn't have either. So the sync had nothing reliable to match on beyond the name it was given.

A trust or company registered more than once under a slightly different name became a second Company record instead of an update to the first. The "Sales Unit Trust" record existed multiple times in the portal before anyone caught it. And because every duplicate attracted jobs that XPM had already associated to that client, a single client's history ended up split across two or three records.

our-approach-header-icon

Our Approach

We first matched Companies by name alone, because it was the field both systems already filled in by default. It broke down against the entity types an accounting practice actually carries, such as two trusts with near-identical names, or a company re-registered under a slightly different string. Each mismatch created a new Company record instead of updating the one that already existed, and the jobs tied to that client scattered across the copies.

So we dropped name matching for XPM's own Client Export Code, a unique identifier that's already stamped on every exported record. We re-keyed both the Company sync and the Jobs-to-Company association to run against it. A batch load now checks the code before it writes a Company record, and it only creates a new one when the code has never been seen.

The trade-off is timing. XPM itself recommends automating this load as the next phase, but for now a newly created client waits for the next batch before it resolves cleanly in HubSpot.

impact-header-icon

Impact

check-icon

Duplicate company records stop compounding

The deduplication workflow, keyed on the Client Export Code, catches a re-exported XPM client before it becomes a second Company record, so the duplicate count is already decreasing as each batch load runs. A trust or SMSF that used to spawn a fresh copy on every name variant now resolves to the one record it should always have been.

check-icon

A client's job history reads as one record, not three

Because Jobs-to-Company inherits the same Client Export Code, a client's XPM jobs attach to the single Company record that survives deduplication, not to whichever duplicate existed when the job synced. A team pulling up that client's HubSpot record sees its full job history in one place.

check-icon

The match survives structures a domain-based system can't see

Trusts, SMSF trustees, and single-purpose companies, the entity types that make up most of an accounting practice's book, now match reliably even though none carry the domain or website HubSpot's own logic looks for. The identifier behind the match comes from the practice-management system itself, so it holds regardless of what a Company record has on the web.

check-icon

The object model is ready for its next system

Checking the design against HubSpot's own record and association ceilings before cutover meant that go-live didn't stall on a data-model problem found after the fact. The same Client Export Code that resolved the deduplication problem is what the next practice-management system will need to match against.

Technical Blueprint
1

The unique identifier XPM stamps on every exported client and job record. Company sync and Jobs-to-Company both key on it instead of the entity name, so a re-exported or renamed client resolves to the Company record that already exists.

2

A scheduled load that checks the Client Export Code against existing Companies before writing a new one, run manually rather than on a live sync. XPM's own recommendation is to automate this load once the identifier match is proven out.

3

The association that attaches a client's XPM jobs to its HubSpot Company record, one of HubSpot's many-to-many associations, rebuilt to run on the Client Export Code so a job resolves to the single deduplicated Company rather than whichever duplicate existed when it last synced.

4

A one-time review confirming the Company and Jobs data model would hold under HubSpot's ceilings on custom objects, a 1,000,000-record cap per object and a 10,000-record association cap, checked against the entity relationship diagrams mapped during discovery before cutover to production.

Diagram of XPM client, company and job records batch-matching into HubSpot Companies by Client Export Code, with jobs following the same key.

Xero Practice Manager exports client, company and job records in a batch, and each one is checked against its Client Export Code before anything is written to HubSpot. A code that's already in HubSpot updates the existing Company, and a code that hasn't been seen creates a new one. Job records follow the same code into the Jobs-to-Company association, so every job lands on the one deduplicated Company. The dashed line shows the earlier name-based match that this replaced.

FAQ

Why can't HubSpot just deduplicate our companies automatically?

HubSpot's native Company deduplication needs a domain or a website to compare records against, and it doesn't have a fallback when a record has neither. If a meaningful share of your Companies are trusts, SMSFs, or single-purpose entities without a web presence, which describes most accounting and advisory practices, the native match has nothing to run on and keeps creating duplicates instead of catching them.

What do we key deduplication on instead?

You key it on whatever unique identifier your source system already assigns to each client or company record, XPM's Client Export Code in this build, rather than the name or the missing domain. The same identifier should carry through to any downstream association, like jobs or cases, so a duplicate never gets the chance to fork a client's history across two records.

Continue reading

Hero featured image
209049082793

Luxury yacht manufacturer: CRM governance, 16.9% MQL-to-SQL

Hero featured image
209049052783

$500M+ telecom provider: one CPQ for MSP and ISP catalogs

Hero featured image
209049052785

Health insurance web broker: NPN hierarchies in HubSpot

Hero featured image
209049052787

$50M+ telehealth provider: HIPAA-compliant clinical ERP sync

Hero featured image
209049052787

$50M+ telehealth provider: attribution recovered via API fix

Hero featured image
209049052786

Environmental IoT provider: partner directory routes leads

Hero featured image
209053190299

$100M+ real estate tech firm: automated KYC gates and SSO

Hero featured image
209049052785

$1B+ financial data provider: Pardot and Eloqua into HubSpot

Hero featured image
209053177394

Global abrasives producer: 40+ sites from Kentico to HubSpot

Hero featured image
209049082792

Global abrasives producer: 13 dashboards consolidated to one

Hero featured image
209049052787

Medical device maker: five regional domains into one CMS

Hero featured image
209049052787

Medical device maker: automated clinical triage in HubSpot

Hero featured image
209049052787

Multi-site dental group: lifecycle logic rebuilt, true ROI

Hero featured image
209049052787

Multi-site dental group: assessment tool for lead quality

Hero featured image
209049082794

K-12 Catholic diocese: 80 schools on one HubDB lead system

Hero featured image
209049052787

Cell therapy biotech: HubSpot CMS migration, 92 speed score

Hero featured image
209049052787

Cell therapy biotech: 40-hour enablement and lead routing

Hero featured image
209049082794

Wellness training provider: 925k records moved to HubSpot

Hero featured image
209049052786

Cybersecurity trainer: 595 workflows audited for debt

Hero featured image
209049052785

Tier 1 auto F&I provider: 14,000% CTA lift, 21% PVR lift

Hero featured image
209049052785

Mexican retail bank: Infobip to Intercom via Apache NiFi

Hero featured image
209049052786

Global streaming platform: ETL middleware feeds Customer.io

Hero featured image
209049052786

Global streaming platform: usage milestones trigger upsell

Hero featured image
209049052786

Cloud and edge provider: Intercom to Salesforce via MuleSoft

Hero featured image
209049052785

$50M+ FinTech SaaS provider: advisor onboarding 30% faster

Hero featured image
209049082792

Mining autonomy provider: global consent and data governance

Hero featured image
209053177394

Industrial IoT division: compliant list purge, leads 3 to 62

Hero featured image
209053177394

Industrial IoT division: 25,000 records merged, one portal

Hero featured image
209049052786

Logistics SaaS portfolio: Salesforce sync rebuilt on Tray.io

Hero featured image
209049052786

Logistics SaaS portfolio: brands consolidated into HubSpot

footerCTA footerCTA-mobile
Spice up your inbox
Sign up for our newsletter
Don't worry - we only average, like, two emojis per subject line.