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

# Pipeline Deals API — Manage Sales Pipeline Deals

> List, create, retrieve, and update pipeline deals. Filter by stage, status, company, or owner, and track deal progression through your pipeline stages.

Pipeline deals represent opportunities moving through your sales process. Each deal is tied to a company and a pipeline stage, and can optionally link to a contact, site, and owner. Moving a deal to a closed-won or closed-lost stage automatically updates its status.

## Required scope

All pipeline endpoints require the `pipeline` scope on your API key.

## Deal statuses

| Status | Meaning                                                             |
| ------ | ------------------------------------------------------------------- |
| `open` | Deal is active and in progress.                                     |
| `won`  | Deal was won. Set automatically when moved to a closed-won stage.   |
| `lost` | Deal was lost. Set automatically when moved to a closed-lost stage. |

***

## List deals

`GET /api/v1/pipeline/deals`

Returns a paginated list of deals for the authenticated tenant.

### Query parameters

<ParamField query="stageId" type="string">
  Filter by pipeline stage UUID.
</ParamField>

<ParamField query="status" type="string">
  Filter by deal status. One of: `open`, `won`, `lost`.
</ParamField>

<ParamField query="companyId" type="string">
  Filter by company UUID.
</ParamField>

<ParamField query="ownerId" type="string">
  Filter by owner (user) UUID.
</ParamField>

<ParamField query="page" type="integer" default="1">
  1-based page index.
</ParamField>

<ParamField query="limit" type="integer" default="25">
  Results per page. Maximum `100`.
</ParamField>

### Response

```json theme={null}
{
  "data": [
    {
      "id": "c4a760a8-dbcf-5a0c-8b5d-48f8e2b18d09",
      "name": "Acme Corp — Enterprise Renewal",
      "value": "45000.00",
      "probability": 65,
      "expectedCloseDate": "2024-09-30",
      "actualCloseDate": null,
      "status": "open",
      "lostReason": null,
      "products": [],
      "notes": null,
      "createdAt": "2024-06-10T09:00:00Z",
      "company": {
        "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
        "name": "Acme Corp"
      },
      "contact": {
        "id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "stage": {
        "id": "b5a6f9e0-1234-4abc-9def-000000000001",
        "name": "Proposal Sent",
        "color": "#3B82F6",
        "probability": 65,
        "isClosedWon": false,
        "isClosedLost": false
      },
      "owner": {
        "id": "user-uuid-here",
        "name": "Sam Chen"
      }
    }
  ],
  "total": 38,
  "page": 1,
  "pageSize": 25
}
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://app.novala.ai/api/v1/pipeline/deals?status=open" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    'https://app.novala.ai/api/v1/pipeline/deals?status=open',
    { headers: { 'Authorization': `Bearer ${apiKey}` } }
  );
  const { data, total } = await response.json();
  ```
</CodeGroup>

***

## Create a deal

`POST /api/v1/pipeline/deals`

Creates a new pipeline deal. The deal's probability is inherited from the stage. Status is set to `open` at creation.

### Request body

<ParamField body="name" type="string" required>
  Deal name. Maximum 200 characters.
</ParamField>

<ParamField body="companyId" type="string" required>
  UUID of the company this deal is with. Must belong to your tenant.
</ParamField>

<ParamField body="stageId" type="string" required>
  UUID of the pipeline stage to place the deal in. Must belong to your tenant.
</ParamField>

<ParamField body="contactId" type="string">
  UUID of the primary contact for this deal.
</ParamField>

<ParamField body="siteId" type="string">
  UUID of the site associated with this deal.
</ParamField>

<ParamField body="ownerId" type="string">
  UUID of the user who owns this deal. Defaults to the authenticated user when using session auth.
</ParamField>

<ParamField body="value" type="string">
  Expected deal value as a decimal string (for example, `"45000.00"`).
</ParamField>

<ParamField body="expectedCloseDate" type="string">
  Expected close date in `YYYY-MM-DD` format.
</ParamField>

<ParamField body="products" type="array">
  Array of product objects associated with the deal.
</ParamField>

<ParamField body="notes" type="string">
  Internal notes about the deal.
</ParamField>

<ParamField body="customFields" type="object">
  Custom field key-value map.
</ParamField>

### Response

Returns `201 Created` with `{ "data": { deal object } }`. Returns `404 Not Found` if `companyId` or `stageId` do not belong to your tenant.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://app.novala.ai/api/v1/pipeline/deals \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Acme Corp — Enterprise Renewal",
      "companyId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
      "stageId": "b5a6f9e0-1234-4abc-9def-000000000001",
      "value": "45000.00",
      "expectedCloseDate": "2024-09-30"
    }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch('https://app.novala.ai/api/v1/pipeline/deals', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Acme Corp — Enterprise Renewal',
      companyId: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
      stageId: 'b5a6f9e0-1234-4abc-9def-000000000001',
      value: '45000.00',
      expectedCloseDate: '2024-09-30',
    }),
  });
  const { data } = await response.json(); // 201 Created
  ```
</CodeGroup>

***

## Get a deal

`GET /api/v1/pipeline/deals/{id}`

Retrieves a deal with its full detail: company, stage, contact, site, owner, and up to 20 recent activities.

### Path parameters

<ParamField path="id" type="string" required>
  UUID of the deal.
</ParamField>

### Response fields

<ResponseField name="data" type="object">
  <Expandable title="Deal object">
    <ResponseField name="id" type="string">UUID of the deal.</ResponseField>
    <ResponseField name="name" type="string">Deal name.</ResponseField>
    <ResponseField name="value" type="string | null">Deal value as a decimal string.</ResponseField>
    <ResponseField name="probability" type="integer">Close probability percentage (0–100), inherited from the stage.</ResponseField>
    <ResponseField name="expectedCloseDate" type="string | null">Expected close date (`YYYY-MM-DD`).</ResponseField>
    <ResponseField name="actualCloseDate" type="string | null">Actual close date, set when the deal is won or lost.</ResponseField>
    <ResponseField name="status" type="string">One of `open`, `won`, `lost`.</ResponseField>
    <ResponseField name="lostReason" type="string | null">Reason for losing the deal.</ResponseField>
    <ResponseField name="products" type="array">Products associated with the deal.</ResponseField>
    <ResponseField name="notes" type="string | null">Internal notes.</ResponseField>
    <ResponseField name="customFields" type="object">Custom field key-value pairs.</ResponseField>
    <ResponseField name="company" type="object">Nested company with `id`, `name`, `phone`, and `email`.</ResponseField>
    <ResponseField name="stage" type="object">Nested stage with `id`, `name`, `color`, `probability`, `isClosedWon`, `isClosedLost`.</ResponseField>
    <ResponseField name="contact" type="object | null">Nested contact with `id`, `firstName`, `lastName`, `email`, `phone`, `role`.</ResponseField>
    <ResponseField name="site" type="object | null">Nested site with `id`, `name`, `address`, `city`, `state`.</ResponseField>
    <ResponseField name="owner" type="object | null">Nested owner with `id`, `name`, `email`.</ResponseField>
    <ResponseField name="activities" type="array">Up to 20 recent activities with `id`, `type`, `description`, `activityDate`, and a nested `user`.</ResponseField>
    <ResponseField name="createdAt" type="string">ISO 8601 creation timestamp.</ResponseField>
    <ResponseField name="updatedAt" type="string">ISO 8601 last-updated timestamp.</ResponseField>
  </Expandable>
</ResponseField>

***

## Update a deal

`PATCH /api/v1/pipeline/deals/{id}`

Partially updates a deal. Only include fields you want to change. Moving a deal to a closed-won or closed-lost stage automatically sets the `status` and `actualCloseDate`.

### Path parameters

<ParamField path="id" type="string" required>
  UUID of the deal.
</ParamField>

### Request body

All fields are optional.

<ParamField body="name" type="string">
  Updated deal name.
</ParamField>

<ParamField body="stageId" type="string">
  UUID of the new stage. Probability updates automatically from the stage. If the stage is marked `isClosedWon`, status becomes `won`; if `isClosedLost`, status becomes `lost`.
</ParamField>

<ParamField body="companyId" type="string">
  Updated company UUID.
</ParamField>

<ParamField body="contactId" type="string | null">
  Updated contact UUID. Pass `null` to remove.
</ParamField>

<ParamField body="siteId" type="string | null">
  Updated site UUID. Pass `null` to remove.
</ParamField>

<ParamField body="ownerId" type="string | null">
  Updated owner UUID. Pass `null` to unassign.
</ParamField>

<ParamField body="value" type="string | null">
  Updated deal value.
</ParamField>

<ParamField body="expectedCloseDate" type="string | null">
  Updated expected close date (`YYYY-MM-DD`). Pass `null` to clear.
</ParamField>

<ParamField body="notes" type="string | null">
  Updated internal notes.
</ParamField>

<ParamField body="customFields" type="object">
  Replaces all custom field values.
</ParamField>

### Response

Returns `200 OK` with `{ "data": { updated deal } }`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH https://app.novala.ai/api/v1/pipeline/deals/c4a760a8-dbcf-5a0c-8b5d-48f8e2b18d09 \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "stageId": "b5a6f9e0-1234-4abc-9def-000000000002",
      "value": "52000.00"
    }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    'https://app.novala.ai/api/v1/pipeline/deals/c4a760a8-dbcf-5a0c-8b5d-48f8e2b18d09',
    {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        stageId: 'b5a6f9e0-1234-4abc-9def-000000000002',
        value: '52000.00',
      }),
    }
  );
  const { data } = await response.json();
  ```
</CodeGroup>
