Account / Contact object models, Cargo automatically resolves and links records that represent the same real-world entity using shared identifiers called references.
The result is four native data models that serve as the canonical source of truth for your workspace: Account, Contact, Account Event, and Contact Event.
Unification runs automatically — there’s nothing to deploy. You consume the unified models like any other, from the CLI or SQL:
Reference a unified model in code
The four unified models are generated by Cargo’s unification — they can’t be created. With the CDK, declaring one with its unify extractor adopts the live model instead of creating it: deploy binds the handle and reconciles its updatable surface (name, description, additional columns, sync schedule, and — on the entity models — the unification settingsconfig), and destroy releases it. The handle then works anywhere a model is referenced:
models/contacts.ts
unifyAccounts, unifyContacts, unifyAccountEvents, and unifyContactEvents — one per unified model.
How unification works
1
Connect data sources
Connect integrations (HubSpot, Salesforce, LinkedIn, etc.) that sync data models into your warehouse. Each integration model declares which unification type it participates in —
account, contact, accountEvent, or contactEvent.2
Map references
Each source model maps its columns to unification references — shared identifiers like
domain, email, or linkedinId. Cargo uses these references to determine which records across different sources represent the same entity.3
Resolve canonical IDs
Cargo builds a mapping table that groups records sharing the same reference values under a single canonical ID. If a HubSpot company and a Salesforce account share the same domain, they receive the same canonical ID.
4
Materialize unified models
The native unified models are materialized as tables in your warehouse, refreshed every 12 hours by default. The sync schedule is editable per model, down to a minimum interval of 5 minutes.
Unified models
Account
The Account model merges company records from all connected integrations into a single, deduplicated table. Each row represents a unique company, identified by a canonical ID computed from shared references.Reference columns (
domain, linkedin_id, etc.) are resolved by taking the highest-priority non-null value across all source records that share the same canonical ID.Contact
The Contact model merges people records from all connected integrations into a single, deduplicated table. Each row represents a unique person, linked to their parent Account viaaccount_id.
The
account_id is resolved through the parent unification mapping — if a source contact model declares a parent relationship to an account model, Cargo automatically links the unified contact to the correct unified account.Account Event
The Account Event model aggregates event data from all connected integrations into a single timeline, where each event is linked to its parent Account.Contact Event
The Contact Event model aggregates event data from all connected integrations into a single timeline, where each event is linked to its parent Contact.References
References are the shared identifiers Cargo uses to match records across integrations. Each unification type supports a specific set of references. Event models inherit the references of their parent type.Account references
Used by the Account and Account Event models.Contact references
Used by the Contact and Contact Event models.Slug matching
The Slug reference is the account’s name, normalized. Slug matching is opt-in — it is"none" by default and does nothing until you enable it in the unification settings below. When enabled, the slug participates like any other weak identifier: identical normalized names corroborate a merge, but never cause one on their own. The slug reference exists on accounts only: person names need different matching semantics (a first+last+domain composite), so contacts carry no slug reference yet.
Slugification. Company names are lowercased, punctuation is stripped, a leading “the” is dropped, trailing legal-entity tokens (Inc, LLC, GmbH, OpCo, …) are removed, and the remaining tokens are dash-joined — so OpenAI, Inc. and OpenAI OpCo LLC both slugify to openai, and The Coca-Cola Company to coca-cola. Brand words like “Labs” are kept (Bell Labs is not Bell), so name variants stay distinct.
Turning it on. Set the slug to "weak" in the unification settings below. It then joins the identifier graph at the same trust level as a Twitter handle: weak identifiers never merge records on their own and can never bridge two strong components, so two accounts with different domains are never merged just because their names look alike. Placeholder slugs (test, unknown, n-a, …) and slugs shared by too many records are ignored entirely.
Unification settings
How references match is configurable per unified model, through the model’s extractor config — via the API (PUT /v1/storage/models/:uuid with config) or in code:
models/accounts.ts
Every reference must be present. New models are seeded with the curated defaults —
domain, email, and the ID-style references are strong, handles and permalinks are weak, and the slug is none (matching is opt-in). Updates must send the complete map back — read the model’s current config, adjust the entries you want, and PUT the whole object back.
The highest-precision way to resolve a name-only record remains enrichment:
resolve the name to a domain with an enrichment play, and the deterministic
domain match takes over from there.
Reference priority
When multiple references match, Cargo uses an ordered reference list to determine which reference takes priority for deduplication. You can configure this order per unified model in the workspace settings. For example, with the default account reference order[domain, linkedinId, linkedinHandle, ...], two records sharing the same domain will be merged even if their linkedinId values differ.
Relationships
The four unified models form a connected graph:Source tracking
Every unified record includes anids column — a JSON object that maps back to the original records from each contributing integration:
id itself is a composite key that encodes the source: <dataset_slug>__<model_slug>__<original_record_id>.
The properties column on event models preserves all original columns from the source record as a JSON object, so no data is lost during unification.
