# CRM

The sales pipeline over client accounts: deals, contacts, notes and the client record.

Generated from contract version `1.0.0` — the same document [`/v1/api/openapi.json`](/api/openapi/) serves.

## Prerequisites

- An API key in `x-api-key`, or a browser session cookie
- `X-Organization-Id` naming the workspace to act in, unless the session already has an active one
- The base URL for your deployment, `https://server.hlix.ai` by default

## Operations

| Method | Path | Operation |
| --- | --- | --- |
| `GET` | `/v1/api/crm/clients/{clientAccountId}` | [Show a client's record: deals, contacts, timeline, projects and invoices](#show-a-clients-record-deals-contacts-timeline-projects-and-invoices) |
| `GET` | `/v1/api/crm/contacts` | [List contacts](#list-contacts) |
| `POST` | `/v1/api/crm/contacts` | [Create a contact](#create-a-contact) |
| `POST` | `/v1/api/crm/deals` | [Create a deal](#create-a-deal) |
| `PATCH` | `/v1/api/crm/deals/{dealId}` | [Move a deal or edit its value, owner and next step](#move-a-deal-or-edit-its-value-owner-and-next-step) |
| `PUT` | `/v1/api/crm/deals/{dealId}/suggestion` | [Replace a deal's suggested next step and draft with your own](#replace-a-deals-suggested-next-step-and-draft-with-your-own) |
| `POST` | `/v1/api/crm/deals/{dealId}/suggestion/regenerate` | [Have the agent write a new suggested next step and draft](#have-the-agent-write-a-new-suggested-next-step-and-draft) |
| `POST` | `/v1/api/crm/notes` | [Add a note to a deal, contact or client timeline](#add-a-note-to-a-deal-contact-or-client-timeline) |
| `GET` | `/v1/api/crm/pipeline` | [Show the pipeline board and the last 30 days of outbound](#show-the-pipeline-board-and-the-last-30-days-of-outbound) |
| `PUT` | `/v1/api/crm/pipeline/stages/{stage}/probability` | [Set the forecast odds of an open pipeline stage](#set-the-forecast-odds-of-an-open-pipeline-stage) |

## Show a client's record: deals, contacts, timeline, projects and invoices

`GET /v1/api/crm/clients/{clientAccountId}` · operation ID `getCrmClientRecord`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `clientAccountId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmClientRecord | The client record; the timeline is newest first. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | No client account with this id in the workspace. |

## List contacts

`GET /v1/api/crm/contacts` · operation ID `listCrmContacts`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `clientAccountId` | query | no | string | Only this client account's contacts. |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmContact[] | Contacts, oldest first. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Create a contact

`POST /v1/api/crm/contacts` · operation ID `createCrmContact`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `CreateContact` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `clientAccountId` | string | **yes** | min length 1 |
| `email` | string (email) | no | max length 320 |
| `linkedinUrl` | string (uri) | no | max length 2048 |
| `name` | string | **yes** | min length 1, max length 200 |
| `sourceNote` | string | no | min length 1, max length 500 |
| `title` | string | no | min length 1, max length 200 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | CrmContact | The new contact. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |

## Create a deal

`POST /v1/api/crm/deals` · operation ID `createCrmDeal`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `CreateDeal` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `clientAccountId` | string | **yes** | min length 1 |
| `currency` | string | no |  |
| `expectedCloseOn` | string (date) | no |  |
| `nextStep` | string | no | min length 1, max length 500 |
| `nextStepAt` | string (date-time) | no |  |
| `ownerUserId` | string | no | min length 1 |
| `sourceKind` | `play` | `referral` | `inbound` | `manual` | **yes** |  |
| `sourcePlayId` | string | no | min length 1 |
| `stage` | string | no | min length 1, max length 100 |
| `valueMicros` | integer | no | min 0, max 9007199254740991 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | CrmDeal | The new deal, in the default pipeline. |
| `400` | ValidationError \| ApiError | A stage the pipeline does not have, a value without a currency, an owner outside the workspace, or subjects of different clients. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |

## Move a deal or edit its value, owner and next step

`PATCH /v1/api/crm/deals/{dealId}` · operation ID `updateCrmDeal`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `dealId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `UpdateDeal` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `currency` | string | null | no |  |
| `expectedCloseOn` | string (date) | null | no |  |
| `lostReason` | string | no | min length 1, max length 500 |
| `nextStep` | string | null | no |  |
| `nextStepAt` | string (date-time) | null | no |  |
| `ownerUserId` | string | null | no |  |
| `stage` | string | no | min length 1, max length 100 |
| `valueMicros` | integer | null | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmDeal | The deal after the change. A stage move is also written to its timeline. |
| `400` | ValidationError \| ApiError | A stage the pipeline does not have, a value without a currency, an owner outside the workspace, or subjects of different clients. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |

## Replace a deal's suggested next step and draft with your own

`PUT /v1/api/crm/deals/{dealId}/suggestion` · operation ID `setCrmDealSuggestion`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `dealId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `DealSuggestion` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `draftBody` | string | null | **yes** |  |
| `draftSubject` | string | null | **yes** |  |
| `step` | string | **yes** | min length 1, max length 200 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmDealSuggestion | The person's version; the agent never overwrites it. |
| `400` | ValidationError | A draft subject without a body. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |

## Have the agent write a new suggested next step and draft

`POST /v1/api/crm/deals/{dealId}/suggestion/regenerate` · operation ID `regenerateCrmDealSuggestion`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `dealId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmRegeneratedSuggestion | The new suggestion, or null when the agent's attempt failed its fact check. |
| `400` | ApiError | The deal is closed. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |
| `502` | ApiError | The agent could not write a suggestion right now. |

## Add a note to a deal, contact or client timeline

`POST /v1/api/crm/notes` · operation ID `addCrmNote`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `CreateNote` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `clientAccountId` | string | no | min length 1 |
| `contactId` | string | no | min length 1 |
| `dealId` | string | no | min length 1 |
| `summary` | string | **yes** | min length 1, max length 4000 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | CrmActivity | The note as a timeline entry. |
| `400` | ValidationError \| ApiError | A stage the pipeline does not have, a value without a currency, an owner outside the workspace, or subjects of different clients. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | A referenced client account, deal, contact or campaign is not in this workspace. |

## Show the pipeline board and the last 30 days of outbound

`GET /v1/api/crm/pipeline` · operation ID `getCrmPipeline`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmBoard | The default pipeline, its deals per stage with value totals, and the outbound funnel. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Set the forecast odds of an open pipeline stage

`PUT /v1/api/crm/pipeline/stages/{stage}/probability` · operation ID `setCrmStageProbability`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `stage` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `StageProbability` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `percent` | integer | null | **yes** |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CrmPipeline | The pipeline with its stage odds. |
| `400` | ValidationError \| ApiError | Not a stage of the pipeline, or not an open stage. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Only an owner or admin can change stage odds. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## If a request fails

These apply to every operation on this page.

- `400` — the body failed schema validation, or the request named no active organization. A `ValidationError` body carries the failing fields; an `ApiError` body carries only `error`.
- `401` — no valid session or API key.
- `403` — authenticated, but not a member of the named organization, or a client collaborator without the required access.
- `404` — no such resource **in this workspace**. Absent and not-visible are deliberately the same answer; do not infer cross-tenant existence from it.
- `409` — the expected revision or state is stale, or another operation currently owns the transition.
- `500` — the operation failed server-side. Retry only where an idempotency key makes that safe.

## Next steps

[API reference](/api/reference/)
  [API & OpenAPI](/api/openapi/)
  [TypeScript SDK](/sdk/typescript/)
  [CLI reference](/reference/cli/)