> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getcargo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Object models

> Native, writable data models for the core entities of your GTM motion

Object models are **native, Cargo-managed data models** for the core entities your team works with — accounts, contacts, deals, leads, and any custom object you need. Unlike integration models that mirror data from an external source, object models are owned by your workspace: your plays, tools, and agents create, update, and remove records in them directly.

Use object models when you need a writable system of record inside Cargo — for example, a list of qualified leads built from research, a pipeline of opportunities sourced from intent signals, or a custom catalog of partners, products, or territories that doesn't live anywhere else.

<Note>
  Object models are stored in the same data warehouse as your integration
  models, which means you can join, query, and unify them using SQL like any
  other model.
</Note>

***

## When to use object models

| Scenario                                    | Why an object model fits                                                                                      |
| :------------------------------------------ | :------------------------------------------------------------------------------------------------------------ |
| **Build a sourced lead list**               | Capture leads from research, scraping, or signals before they exist in your CRM.                              |
| **Maintain an internal pipeline**           | Track deals, accounts, or campaigns that aren't synced from a connected system.                               |
| **Persist agent and play outputs**          | Let agents write structured results (qualified accounts, recommended plays, etc.) into a queryable table.     |
| **Model entities you don't have a CRM for** | Partners, vendors, products, territories, content assets, or any custom object specific to your business.     |
| **Unify writable data with integrations**   | Object Account / Contact records participate in [unification](/reference/models/unification) like any source. |

For models that **mirror** data from an external system (HubSpot, Salesforce, Snowflake, a webhook, etc.), use [integration models](/reference/models/overview#model-types) instead.

***

## Built-in object types

Cargo ships five native object types. The first four come pre-shaped with the standard fields for their entity, so you can start writing records immediately and they will participate in unification out of the box.

<CardGroup cols={2}>
  <Card title="Account" icon="building">
    A company. Pre-mapped with `name`, `website`, `linkedin_url`, `industry`,
    `number_of_employees`, `annual_revenue`, billing address, owner, and parent
    account.
  </Card>

  <Card title="Contact" icon="user">
    A person tied to an account. Pre-mapped with first/last name, `email`,
    `phone`, `title`, `linkedin_url`, mailing address, lead source, and owner.
  </Card>

  <Card title="Deal" icon="circle-dollar">
    An opportunity tied to an account. Pre-mapped with `amount`,
    `stage_name`, `close_date`, `probability`, `forecast_category`,
    `is_closed`, `is_won`, owner, and campaign.
  </Card>

  <Card title="Lead" icon="user-plus">
    An unqualified person + company combined into one record. Includes
    conversion fields (`is_converted`, `converted_account_id`,
    `converted_contact_id`, `converted_opportunity_id`) for handoff to
    Account/Contact.
  </Card>

  <Card title="Custom" icon="table">
    An object you define from scratch. Pick the columns and types you need —
    `string`, `number`, `boolean`, `date`, `object`, `array`, or `vector`.
  </Card>
</CardGroup>

Each built-in type has a default `id` column (a Cargo-generated UUID on insert) and a sensible title column (`name` for Account/Contact/Deal/Lead, `id` for Custom).

<Tip>
  Need a field that isn't on the built-in schema? Add a [custom
  column](/reference/actions/overview#model-custom-column) — your plays can
  upsert values into it without changing the underlying schema.
</Tip>

***

## How object models compare

| Capability                            | Object model                        | Integration model                          | Unified model                    |
| :------------------------------------ | :---------------------------------- | :----------------------------------------- | :------------------------------- |
| Source of records                     | Cargo plays, agents, tools, API     | External system (CRM, warehouse, webhook…) | Computed from other models       |
| Writable from a workflow              | ✅ Insert / update / upsert / remove | ❌ Use the integration's own write actions  | ❌ Read-only                      |
| Schema control                        | ✅ Built-in or fully custom          | ❌ Fixed by the source                      | ❌ Fixed by Cargo                 |
| Participates in unification           | ✅ Account & Contact types           | ✅ When the integration declares a type     | n/a (it *is* the unified output) |
| Triggers plays on change              | ✅                                   | ✅                                          | ✅                                |
| Available in Model search / Model ask | ✅                                   | ✅                                          | ✅                                |

***

## Writing to an object model

Object models are designed to be written to from inside Cargo. The Storage actions below all target object models specifically — when you pick a model in the node configuration, only object models appear in the picker.

| Action           | What it does                                                 |
| :--------------- | :----------------------------------------------------------- |
| **Model insert** | Add one or more new records. The `id` is generated by Cargo. |
| **Model update** | Update records matching a column / value pair.               |
| **Model upsert** | Update matching records, or insert a new one if none match.  |
| **Model remove** | Delete records matching a column / value pair.               |

<Steps>
  <Step title="Pick a target object model">
    Use the **Model** dropdown on any of the actions above. The dropdown is
    scoped to native objects — integration models and unified models are
    intentionally hidden.
  </Step>

  <Step title="(For update / upsert / remove) choose a matching column">
    Cargo will resolve every record where the matching column equals the
    matching value. Use a unique column (typically `id`, `email`, or `website`)
    to avoid touching unintended rows.
  </Step>

  <Step title="Map the values">
    Provide a value for each column you want to write. Values support
    [expressions](/get-started/expressions-cheatsheet) (e.g.
    `{{nodes.start.email}}`).
  </Step>
</Steps>

<Warning>
  `id` is generated by Cargo on insert and cannot be supplied. For updates and
  upserts, do **not** include `id` in the column mappings — use it as the
  matching column instead.
</Warning>

***

## Object models and unification

`Account` and `Contact` object models declare a [unification type](/reference/models/unification) by default, so the records you write into them roll up into the unified `Account` and `Contact` models alongside your CRM, enrichment, and other sources.

| Object type | Unifies as | Default reference columns                                                             |
| :---------- | :--------- | :------------------------------------------------------------------------------------ |
| **Account** | `account`  | `website` → `domain`, `linkedin_url` → `linkedinHandle`, `linkedin_id` → `linkedinId` |
| **Contact** | `contact`  | `email` → `email`, `linkedin_url` → `linkedinHandle`, `linkedin_id` → `linkedinId`    |
| **Deal**    | `account`  | (no default reference columns — link via `account_id`)                                |

This means an account you create from a research agent, a contact you upsert from a webhook, and a company synced from HubSpot all collapse into the same canonical record when they share a domain or LinkedIn identifier.

<Note>
  Lead and Custom object models don't participate in unification. Convert leads
  to Account / Contact records (using the `converted_account_id` /
  `converted_contact_id` fields) once they qualify.
</Note>

***

## Querying object models

Like every model in Cargo, object models materialize as a table in your data warehouse. They follow the same [table naming convention](/reference/models/querying-data) as integration models, under the `native` dataset:

```sql theme={null}
SELECT *
FROM CARGO_DB.datasets_native.models_<MODEL_SLUG>
```

You can join object models with integration or unified models freely — for example, find every sourced lead whose company already exists in your unified `Account` model:

```sql theme={null}
SELECT
  l.id            AS lead_id,
  l.email,
  l.company,
  a.id            AS unified_account_id
FROM CARGO_DB.datasets_native.models_sourced_leads l
LEFT JOIN CARGO_DB.unified.accounts a
  ON LOWER(l.website) = a.domain
WHERE a.id IS NOT NULL
```

***

## Next steps

<CardGroup cols={2}>
  <Card title="Models overview" icon="table" href="/reference/models/overview">
    See how object models fit alongside integration and unified models.
  </Card>

  <Card title="Unification" icon="diagram-project" href="/reference/models/unification">
    Learn how Account and Contact object records merge with CRM and enrichment
    data.
  </Card>

  <Card title="Storage actions" icon="hard-drive" href="/reference/actions/overview#storage">
    Insert, update, upsert, and remove records from your plays and tools.
  </Card>

  <Card title="Querying data" icon="code" href="/reference/models/querying-data">
    Query object models with SQL alongside the rest of your warehouse.
  </Card>
</CardGroup>
