> ## 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" }`.

`landbase-cli account users` — the users of the active account you can assign
campaigns or dialer sessions to (Account Owners see every current member;
everyone else sees only themselves):

```json theme={null}
{
  "data": [
    {
      "identityId": "idn_01H...",
      "firstName": "Sarah",
      "lastName": "Chen",
      "email": "sarah@acme.com",
      "roleId": 2,
      "roleName": "Member",
      "hasActiveInboxes": true,
      "hasConnectedLinkedin": false
    }
  ]
}
```

| Field | Type | Description |
| - | - | - |
| `data[].identityId` | string | What `email-campaigns`, `linkedin-campaigns`, and `dialer-sessions` take as `assignedUserId` on create; campaign commands also take it through `--user` on assign |
| `data[].firstName` | string or null | First name |
| `data[].lastName` | string or null | Last name |
| `data[].email` | string or null | Email address |
| `data[].roleId` | number | Role id in this account |
| `data[].roleName` | string | Role name in this account |
| `data[].hasActiveInboxes` | boolean | Has at least one active sending inbox (required to launch an email campaign assigned to this user) |
| `data[].hasConnectedLinkedin` | boolean | Has a connected LinkedIn account (required to launch a LinkedIn campaign assigned to this user) |

***

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

***

## dialer-sessions

`landbase-cli dialer-sessions create --json session.json`:

```json theme={null}
{
  "sessionId": 9,
  "name": "Q3 outbound calls",
  "status": "new",
  "contactsCount": 42
}
```

| Field | Type | Description |
| - | - | - |
| `sessionId` | number | Numeric id used with `dialer-sessions status` |
| `name` | string | Session name |
| `status` | string | Current session status |
| `contactsCount` | number | Primary rows created from tag contacts with phone availability `AVAILABLE` or `TO_ENRICH`, capped at 1,000; `0` is a successful empty result |

`landbase-cli dialer-sessions status 9`:

```json theme={null}
{
  "sessionId": 9,
  "name": "Q3 outbound calls",
  "status": "new",
  "createdAt": "2026-08-20T12:00:00Z",
  "createdBy": "idn_creator",
  "enrichmentType": "PHONE",
  "owner": {
    "identityId": "idn_owner",
    "firstName": "Ann",
    "lastName": "Lee",
    "email": "ann@example.com"
  },
  "contacts": {
    "total": 42,
    "byDialStatus": { "new": 30, "to_enrich": 10, "answered": 2 }
  }
}
```

| Field | Type | Description |
| - | - | - |
| `createdAt` | string or null | Session creation timestamp, when present |
| `createdBy` | string or null | Creator `identityId`; can be `null` for sessions created in the web app |
| `enrichmentType` | string | `PHONE`, `ALL`, `EMAIL`, or `NONE`, when present |
| `owner` | object | Assigned owner's identity and contact fields, when present |
| `contacts.total` | number | Current total contacts in the session, when counts are present |
| `contacts.byDialStatus` | object | Live contact counts keyed by server-provided dial status, when counts are present |

See [dialer-sessions](https://www.landbase.com/docs/reference/dialer-sessions.md) for the create body and full
workflow.

***

## Error response (stderr)

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

***

## Related

* [error codes reference](https://www.landbase.com/docs/reference/error-codes.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.