> ## 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.

## Create an object model from the CLI

Object models are owned by Cargo. You can create them and their columns imperatively with the `storage` commands, or declaratively in code with the CDK ([see below](#define-an-object-model-in-code)):

```bash theme={null}
cargo-ai storage dataset list                     # → the native datasetUuid

# Create a custom object model
cargo-ai storage model create \
  --slug sourced_leads --name "Sourced Leads" \
  --dataset-uuid <datasetUuid> --extractor-slug csv --config '{}'

# Add columns
cargo-ai storage column create --model-uuid <model-uuid> \
  --column '{"slug":"email","type":"string","label":"Email","kind":"custom"}'
cargo-ai storage column create --model-uuid <model-uuid> \
  --column '{"slug":"website","type":"string","label":"Website","kind":"custom"}'
```

<Note>
  Object models are stored in the same data warehouse as your integration
  models, so you can join, query, and unify them using SQL like any other model.
  The built-in `Account` / `Contact` / `Deal` / `Lead` types ship pre-shaped —
  you only add columns for fields beyond their standard schema.
</Note>

## Define an object model in code

Not every model sits behind a connector. With the [CDK](/get-started/project-layout), pass `kind: "native"` to [`defineModel`](/models/overview) to declare an object model in the workspace's built-in dataset — `defineCustom` for a free-form schema, or the CRM-shaped `defineAccount` / `defineContact` / `defineDeal` / `defineLead`:

```ts models/companies.ts theme={null}
import { defineModel } from "@cargo-ai/cdk";

export const companies = defineModel("companies", {
  kind: "native",
  extractSlug: "defineCustom",
  config: { columns: [{ slug: "domain", type: "string" }] },
});
```

<Note>
  Deploying binds the model into `cargo.state.json`, so your plays, tools, and
  agents can reference it by handle. To adopt one of the four **unified** models
  from code instead, see [Unification](/models/unification#reference-a-unified-model-in-code).
</Note>

## Link models with relationships

[Relationships](/models/relationships) join two object models in the same dataset. Declare them in code with `defineRelationship`, referencing the CLI-created models by `modelRef(uuid)`:

```ts relationships/contact-account.ts theme={null}
import { defineRelationship, modelRef } from "@cargo-ai/cdk";

export const contactAccount = defineRelationship("contact-account", {
  from: { model: modelRef("<contacts-uuid>"), column: "account_id" },
  to: { model: modelRef("<accounts-uuid>"), column: "id" },
  relation: "manyToOne",
});
```

<Note>
  Not using the CDK? Set the same join from the CLI with `cargo-ai storage
      relationship set --dataset-uuid <uuid> --relationships '<json array>'` — see
  [Relationships](/models/relationships) for the field reference.
</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](/models/unification) like any source.       |

For models that **mirror** data from an external system (HubSpot, Salesforce, Snowflake, a webhook, etc.), use [integration models](/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](/models/overview) with `storage column create` — 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 — from the storage steps in a [workflow](/workflows/overview) that backs a play or tool. 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](/reference/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](/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`, `name` → `slug`, `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](/models/querying) 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.object.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="/models/overview">
    See how object models fit alongside integration and unified models.
  </Card>

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

  <Card title="Workflows" icon="diagram-project" href="/workflows/overview">
    Insert, update, upsert, and remove records from your plays and tools.
  </Card>

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