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

# Output schemas

> JSON response shapes for landbase-cli commands — search, match, enrich, contact-enrich, datasets, and workflow responses.

# Output schemas

All landbase-cli commands write JSON to stdout on success. This page documents the shape of each command's response.

***

## search / default query

```json theme={null}
{
  "run_id": "run_abc123",
  "session_id": "ses_xyz789",
  "dataset_id": "ds_def456",
  "status": "complete",
  "content": "Found 142 B2B SaaS companies in New York...",
  "created_at": "2026-06-05T10:00:00Z"
}
```

| Field        | Type   | Description                              |
| ------------ | ------ | ---------------------------------------- |
| `run_id`     | string | ID of this agent run                     |
| `session_id` | string | UUID of the session this run belongs to  |
| `dataset_id` | string | ID of the dataset created by this search |
| `status`     | string | `complete`, `failed`, or `pending`       |
| `content`    | string | Plain-English summary of results         |
| `created_at` | string | ISO 8601 timestamp                       |

***

## match person / match company

```json theme={null}
{
  "result": {
    "tier": "strong",
    "match_reason": "Matched on LinkedIn URL and company domain",
    "candidate": {
      "member_name_first": "Sarah",
      "member_name_last": "Chen",
      "member_websites_linkedin": "https://www.linkedin.com/in/sarahchen",
      "member_title": "VP of Sales",
      "company_domain": "acme.com",
      "company_name": "Acme Corp"
    }
  }
}
```

| Field                 | Type   | Description                                    |
| --------------------- | ------ | ---------------------------------------------- |
| `result.tier`         | string | `strong`, `likely`, `plausible`, or `unlikely` |
| `result.match_reason` | string | Human-readable explanation of match signals    |
| `result.candidate`    | object | The matched record's fields                    |

***

## enrich

```json theme={null}
{
  "person": {
    "member_name_first": "Sarah",
    "member_name_last": "Chen",
    "member_title": "VP of Sales",
    "member_seniority": "vp",
    "member_department": "sales",
    "member_websites_linkedin": "https://www.linkedin.com/in/sarahchen"
  },
  "company": {
    "company_name": "Acme Corp",
    "company_domain": "acme.com",
    "company_industry": "Software",
    "company_size_range": "51-200",
    "company_hq_city": "New York",
    "company_hq_state": "NY",
    "company_hq_country": "United States"
  }
}
```

Fields present depend on which `--company-fields` or `--person-fields` you requested. Absent fields were not requested or not available.

***

## contact-enrich submit (with --wait)

```json theme={null}
{
  "request_id": "cer_abc123",
  "status": "SUCCEEDED",
  "results": [
    {
      "first_name": "Sarah",
      "last_name": "Chen",
      "email": "sarah.chen@acme.com",
      "phone": "+14155551234",
      "linkedin_url": "https://www.linkedin.com/in/sarahchen",
      "company_domain": "acme.com"
    }
  ],
  "total": 1,
  "enriched": 1,
  "failed": 0
}
```

| Field             | Type             | Description                                             |
| ----------------- | ---------------- | ------------------------------------------------------- |
| `request_id`      | string           | ID to retrieve this job later with `contact-enrich get` |
| `status`          | string           | `SUCCEEDED`, `FAILED`, or `USER_REJECTED`               |
| `results`         | array            | One object per input contact                            |
| `results[].email` | string or absent | Work email if found                                     |
| `results[].phone` | string or absent | Direct phone if found and `--enrich-phone` was passed   |
| `total`           | number           | Total contacts submitted                                |
| `enriched`        | number           | Contacts with at least one enriched field               |
| `failed`          | number           | Contacts that could not be processed                    |

***

## contact-enrich submit (without --wait)

```json theme={null}
{
  "request_id": "cer_abc123",
  "status": "PENDING"
}
```

Use `landbase-cli contact-enrich get <request_id>` to retrieve results when the job completes.

***

## datasets list

```json theme={null}
[
  {
    "id": "ds_abc123",
    "name": "CRM Export Jun 2026",
    "created_at": "2026-06-05T10:00:00Z",
    "row_count": 142,
    "status": "ready"
  }
]
```

***

## datasets show

```json theme={null}
{
  "id": "ds_abc123",
  "name": "CRM Export Jun 2026",
  "created_at": "2026-06-05T10:00:00Z",
  "row_count": 142,
  "status": "ready",
  "fields": ["company_name", "company_domain", "industry"],
  "runs": []
}
```

`runs` is populated when `--include-runs` is passed.

***

## upload

```json theme={null}
{
  "id": "ds_abc123",
  "name": "CRM Export Jun 2026",
  "status": "ready"
}
```

***

## workflow trigger (without --wait)

```json theme={null}
{
  "workflow_run_id": "wfr_abc123",
  "dataset_id": "ds_abc123",
  "status": "pending"
}
```

***

## runs list

```json theme={null}
[
  {
    "run_id": "run_abc123",
    "session_id": "ses_xyz789",
    "dataset_id": "ds_def456",
    "status": "complete",
    "content": "Found 142 B2B SaaS companies...",
    "created_at": "2026-06-05T10:00:00Z"
  }
]
```

***

## account

`landbase-cli account` (no args) — the active account, read from local config:

```json theme={null}
{
  "accountId": "4821",
  "source": "config"
}
```

| Field       | Type           | Description                                               |
| ----------- | -------------- | --------------------------------------------------------- |
| `accountId` | string or null | The active account id, or `null` if none is set           |
| `source`    | string         | `"config"` when an account is set, `"none"` when it isn't |

`landbase-cli account list` — every account the user can access:

```json theme={null}
{
  "accounts": [
    { "id": "4821", "name": "Acme Corp", "role": "owner", "current": true },
    { "id": "5093", "name": "Beta LLC", "role": "member", "current": false }
  ]
}
```

| Field                | Type    | Description                        |
| -------------------- | ------- | ---------------------------------- |
| `accounts[].id`      | string  | Account id                         |
| `accounts[].name`    | string  | Account display name               |
| `accounts[].role`    | string  | The user's role in this account    |
| `accounts[].current` | boolean | Whether this is the active account |

`landbase-cli account set` prints the newly active account: `{ "accountId": "5093" }`.

***

## onboarding get

```json theme={null}
{
  "accountId": 4821,
  "sections": {
    "aboutCompany": { "description": "We sell AI-powered prospecting tools." },
    "aboutAudience": {},
    "aboutCompetition": {}
  },
  "schema": [
    {
      "section": "aboutCompany",
      "field": "description",
      "question": "What does your company do?",
      "type": "string",
      "required": true,
      "filled": true,
      "currentValue": "We sell AI-powered prospecting tools."
    }
  ]
}
```

| Field       | Type   | Description                                                                                       |
| ----------- | ------ | ------------------------------------------------------------------------------------------------- |
| `accountId` | number | The account this profile belongs to                                                               |
| `sections`  | object | Current values for `aboutCompany`, `aboutAudience`, `aboutCompetition`                            |
| `schema`    | array  | One entry per field: `section`, `field`, `question`, `type`, `required`, `filled`, `currentValue` |

Iterate `schema` and ask the user the `question` verbatim for every entry where
`required` is `true` and `filled` is `false`, then submit one `update` combining
the answers.

***

## onboarding update

Request body — a partial payload; at least one section is required:

```json theme={null}
{
  "aboutCompany": { "description": "..." },
  "aboutAudience": { "...": "..." },
  "aboutCompetition": { "...": "..." }
}
```

The response echoes the updated profile in the same shape as `onboarding get`.

**Partial-merge rules.** `aboutCompany` and `aboutCompetition` are
partial-mergeable — send only the fields you're changing and the server spreads
them over current state. `aboutAudience` must be a **complete** segment (every
required audience field in one payload); the validator rejects partials.

**Field types** (per `schema.type` — what to put on the wire):

| Type              | Wire shape                                                                 |
| ----------------- | -------------------------------------------------------------------------- |
| `string`          | plain string                                                               |
| `string[]`        | non-empty array of strings                                                 |
| `number`          | JSON number (only `productId` today)                                       |
| `numberRange`     | `{ "min": "50", "max": "500" }` — both values are **strings**, not numbers |
| `customerQuote[]` | non-empty array of `{ quote, customerName }`                               |

**Clear a field.** The merge is a JS object spread (`{ ...current, ...incoming }`),
so the incoming value wins — including `null` and `[]`. To clear a field, send it
explicitly with a falsy/empty value, e.g.
`{ "aboutCompany": { "customerCount": null, "painPoints": [] } }`. Omitting a
field preserves its prior value. Clearing a required field flips it back to
`filled: false` and the validator may reject the next `update` until it's refilled.

***

## contacts-import

`contacts-import start` response (`202 Accepted`):

```json theme={null}
{
  "importId": 7,
  "runRef": "<opaque task ref>"
}
```

`runRef` is for audit only — don't branch on it. Processing is asynchronous; poll
`status <importId>` until `phase` is terminal.

`contacts-import status` / `wait` / `start --watch` final status — a compact,
stable shape (keys present in every phase, `null` until known):

```json theme={null}
{
  "importId": 7,
  "phase": "completed",
  "percent": 100,
  "counts": {
    "total": 952,
    "imported": 940,
    "merged": 12,
    "skipped": 40,
    "invalid": 8
  },
  "error": null
}
```

| Field             | Type           | Description                                                              |
| ----------------- | -------------- | ------------------------------------------------------------------------ |
| `importId`        | number         | The import id                                                            |
| `phase`           | string         | `draft`, `preparing`, `in_progress`, `completed`, `partial`, or `failed` |
| `percent`         | number or null | Progress `0`–`100`; `null` until `totalRows` is known                    |
| `counts.total`    | number or null | Rows to process (raw − skipped − invalid)                                |
| `counts.imported` | number or null | Rows written                                                             |
| `counts.merged`   | number or null | Rows merged into existing contacts                                       |
| `counts.skipped`  | number or null | Rows skipped                                                             |
| `counts.invalid`  | number or null | Rows rejected as invalid                                                 |
| `error`           | string or null | Short reason; set only on `failed` / `partial`                           |

***

## email-campaigns status

```json theme={null}
{
  "campaignId": 123,
  "name": "Q2 outreach",
  "status": "scheduled",
  "stats": { "delivered": 120, "replies": 4, "bounced": 2, "contacted": 122 },
  "outreach": { "inQueue": 30, "inProgress": 5, "completed": 122 },
  "excluded": { "unsubscribed": 3, "no_valid_email": 7 },
  "timing": { "estimatedDaysToCompletion": 6, "dailyCapacity": 50 }
}
```

| Field        | Type   | Description                                       |
| ------------ | ------ | ------------------------------------------------- |
| `campaignId` | number | The campaign id                                   |
| `name`       | string | Campaign name (optional)                          |
| `status`     | string | Lifecycle status                                  |
| `stats`      | object | Delivery funnel counters (optional)               |
| `outreach`   | object | `{ inQueue, inProgress, completed }` (optional)   |
| `excluded`   | object | Exclusion counts by reason (optional)             |
| `timing`     | object | Timing estimates; values may be `null` (optional) |

***

## email-campaigns list

```json theme={null}
{
  "data": [
    { "campaignId": 123, "name": "Q2 outreach", "status": "scheduled" }
  ],
  "totalCount": 1
}
```

| Field        | Type   | Description                                                      |
| ------------ | ------ | ---------------------------------------------------------------- |
| `data`       | array  | Campaigns, newest first — each `{ campaignId, name, status, … }` |
| `totalCount` | number | Total campaigns on the account                                   |

***

## linkedin-campaigns status

```json theme={null}
{
  "campaignId": 456,
  "name": "LinkedIn — Q2 leads",
  "status": "scheduled",
  "campaignType": "linkedin",
  "stats": { "allocated": 240, "sent": 18 }
}
```

| Field          | Type   | Description                        |
| -------------- | ------ | ---------------------------------- |
| `campaignId`   | number | The campaign id                    |
| `name`         | string | Campaign name (optional)           |
| `status`       | string | Lifecycle status                   |
| `campaignType` | string | Campaign type (optional)           |
| `stats`        | object | Allocated/sent counters (optional) |

***

## linkedin-campaigns list

```json theme={null}
{
  "data": [
    { "campaignId": 456, "name": "LinkedIn — Q2 leads", "status": "scheduled" }
  ],
  "totalCount": 1
}
```

Same shape as [email-campaigns list](#email-campaigns-list).

***

## Error response (stderr)

```json theme={null}
{
  "error": {
    "code": "AUTH_FAILED",
    "message": "No valid API key or session found.",
    "meta": {}
  }
}
```

***

## Related

* [error codes reference](/docs/reference/error-codes)
* [How to filter with jq](/docs/how-to/filter-with-jq) — working with these schemas in scripts
