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

# Listing & filters

> Search, pagination, sorting, and structured filters in API v2 list endpoints

# Listing & filters

List endpoints in API v2 share the same query model used in the Heffl app. This applies to `GET /contacts`, `GET /companies`, `GET /deals`, `GET /quotations`, `GET /leads`, and `GET /tasks`.

<Note>
  Pass `filters` as a **JSON-encoded string** in the query (use `curl -G` with `--data-urlencode`). Example: `filters={"status":{"operator":"is","values":["ACTIVE"]}}`. Do not rely on nested query-object encoding — JSON in one query parameter is the supported approach for agents and integrations.
</Note>

## Query parameters

| Parameter  | Type   | Default     | Description                                            |
| ---------- | ------ | ----------- | ------------------------------------------------------ |
| `cursor`   | string | *none*      | Cursor from the previous response (`meta.nextCursor`)  |
| `pageSize` | number | 30          | Items per page (max 100)                               |
| `search`   | string | *none*      | Full-text search (fields vary by endpoint — see below) |
| `orderBy`  | string | `createdAt` | Sort field (allowed values vary by endpoint)           |
| `orderDir` | string | `desc`      | Sort direction: `asc` or `desc`                        |
| `filters`  | object | *none*      | Structured filters (see below)                         |

<Note>
  API v2 list endpoints use `pageSize`, not `limit`. Legacy v1 endpoints still use `limit`.
</Note>

## Basic list

```bash theme={null}
curl "https://api.heffl.com/api/v2/contacts?pageSize=25" \
  -H "x-api-key: YOUR_API_KEY"
```

## Search

```bash theme={null}
curl "https://api.heffl.com/api/v2/contacts?search=jane%40example.com" \
  -H "x-api-key: YOUR_API_KEY"
```

## Sorting

```bash theme={null}
curl "https://api.heffl.com/api/v2/contacts?orderBy=name&orderDir=asc" \
  -H "x-api-key: YOUR_API_KEY"
```

## Structured filters

Each filter field accepts an object with `operator` and `values`:

```json theme={null}
{
  "stageId": {
    "operator": "is",
    "values": ["cs_abc123"]
  }
}
```

Pass filters as a JSON-encoded query parameter:

```bash theme={null}
curl -G "https://api.heffl.com/api/v2/contacts" \
  -H "x-api-key: YOUR_API_KEY" \
  --data-urlencode 'filters={"stageId":{"operator":"is","values":["cs_abc123"]}}'
```

### Available contact and company filters

| Field         | Type         | Value type         | Example operators                                                                               |
| ------------- | ------------ | ------------------ | ----------------------------------------------------------------------------------------------- |
| `stageId`     | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `leadStageId` | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `ownerUserId` | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `createdById` | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `listId`      | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `tagId`       | multi-option | string (ID)        | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `createdAt`   | date         | ISO 8601 date-time | `is`, `is_before`, `is_after`, `is_between`, …                                                  |

Option and tag filters take **string IDs** — the same prefixed IDs returned by the API (for example `cs_abc123`, `usr_xyz789`, `tag_def456`). Date filters take ISO 8601 strings. `GET /contacts` always returns contacts only and `GET /companies` always returns companies only — you do not need to pass a `type` filter. Both support `search` on name, number, email, and phone, and `orderBy` of `createdAt`, `name`, or `number`.

### Available deal filters

| Field               | Type         | Value type                     | Example operators                                                                               |
| ------------------- | ------------ | ------------------------------ | ----------------------------------------------------------------------------------------------- |
| `clientId`          | option       | contact or company ID (`clt_`) | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `pipelineId`        | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `stageId`           | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `status`            | option       | `ACTIVE`, `WON`, `LOST`        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `priority`          | option       | `LOW`, `MEDIUM`, `HIGH`        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `ownerUserId`       | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `crmSourceId`       | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `createdById`       | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `listId`            | option       | string (ID)                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `tagId`             | multi-option | string (ID)                    | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `services`          | multi-option | string (ID)                    | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `createdAt`         | date         | ISO 8601 date-time             | `is`, `is_before`, `is_after`, `is_between`, …                                                  |
| `expectedCloseDate` | date         | ISO 8601 date-time             | `is`, `is_before`, `is_after`, `is_between`, …                                                  |

Deals support `search` on title, number, and client name, and `orderBy` of `createdAt`, `position`, `expectedCloseDate`, or `price`. Client IDs use the `clt_` prefix; pipeline and stage IDs use `dpl_` and `dps_`; product filters use `prd_`. See [ID prefixes](https://docs.heffl.com/api-v2/id-prefixes).

### Available lead filters

| Field              | Type         | Value type         | Example operators                                                                               |
| ------------------ | ------------ | ------------------ | ----------------------------------------------------------------------------------------------- |
| `stageId`          | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `ownerUserId`      | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `assignedTo`       | multi-option | string (ID)        | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `tagId`            | multi-option | string (ID)        | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `crmSourceId`      | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `listId`           | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `archived`         | option       | boolean            | `is`, `is_not`                                                                                  |
| `createdAt`        | date         | ISO 8601 date-time | `is`, `is_before`, `is_after`, `is_between`, …                                                  |
| `nextActivityDate` | date         | ISO 8601 date-time | `is`, `is_before`, `is_after`, `is_between`, …                                                  |
| `createdById`      | option       | string (ID)        | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |

Leads support `search` on name, title, mobile, email, secondary mobile, and website, and `orderBy` of `createdAt`, `position`, `name`, or `value`. Stage IDs use the `lstg_` prefix; assignee and owner filters use `usr_`; tags use `tag_`.

### Available task filters

| Field         | Type         | Value type                                                 | Example operators                                                                               |
| ------------- | ------------ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `status`      | option       | `OPEN`, `IN_PROGRESS`, `ON_HOLD`, `COMPLETED`, `CANCELLED` | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `type`        | option       | `call`, `todo`, `meeting`                                  | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `priority`    | option       | `LOW`, `MEDIUM`, `HIGH`                                    | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `createdById` | option       | string (ID)                                                | `is`, `is_not`, `is_any_of`, `is_none_of`                                                       |
| `assigneeIds` | multi-option | string (ID)                                                | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `tagIds`      | multi-option | string (ID)                                                | `include`, `exclude`, `include_any_of`, `include_all_of`, `exclude_if_any_of`, `exclude_if_all` |
| `createdAt`   | date         | ISO 8601 date-time                                         | `is`, `is_before`, `is_after`, `is_between`, …                                                  |
| `startDate`   | date         | ISO 8601 date-time                                         | `is`, `is_before`, `is_after`, `is_between`, …                                                  |
| `dueDate`     | date         | ISO 8601 date-time (due date)                              | `is`, `is_before`, `is_after`, `is_between`, …                                                  |

Tasks support `search` on title, number, and description, and `orderBy` of `createdAt`, `dueDate`, `startDate`, `number`, or `title`. Assignee and tag filters use `usr_` and `tag_` prefixes.

### Available quotation filters

| Field              | Type         | Value type                              | Example operators                              |
| ------------------ | ------------ | --------------------------------------- | ---------------------------------------------- |
| `status`           | option       | `DRAFT`, `SENT`, `ACCEPTED`, `REJECTED` | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `clientId`         | option       | contact or company ID (`clt_`)          | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `contactId`        | option       | contact person ID (`clt_`)              | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `salesPersonId`    | option       | string (ID)                             | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `createdById`      | option       | string (ID)                             | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `tagId`            | multi-option | string (ID)                             | `include`, `exclude`, `include_any_of`, …      |
| `productId`        | multi-option | string (ID)                             | `include`, `exclude`, `include_any_of`, …      |
| `templateId`       | option       | string (ID)                             | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `dealId`           | option       | string (ID)                             | `is`, `is_not`, `is_any_of`, `is_none_of`      |
| `subject`          | text         | string                                  | `contains`, `does_not_contain`, …              |
| `number`           | text         | string                                  | `contains`, `does_not_contain`, …              |
| `date`             | date         | ISO 8601 date-time                      | `is`, `is_before`, `is_after`, `is_between`, … |
| `expiryDate`       | date         | ISO 8601 date-time                      | `is`, `is_before`, `is_after`, `is_between`, … |
| `markedAcceptedOn` | date         | ISO 8601 date-time                      | `is`, `is_before`, `is_after`, `is_between`, … |
| `createdAt`        | date         | ISO 8601 date-time                      | `is`, `is_before`, `is_after`, `is_between`, … |

Quotations support `search` on number, subject, client name, and line item text. `orderBy` accepts `createdAt`, `date`, `number`, or `expiryDate`. Client IDs use `clt_`; deal IDs use `dl_`; template IDs use `tpl_`; product filters use `prd_`. See [ID prefixes](https://docs.heffl.com/api-v2/id-prefixes).

```bash theme={null}
curl -G "https://api.heffl.com/api/v2/deals" \
  -H "x-api-key: YOUR_API_KEY" \
  --data-urlencode 'filters={"pipelineId":{"operator":"is","values":["dpl_abc123"]},"status":{"operator":"is","values":["ACTIVE"]}}'
```

### Filter examples

Owner is a specific user:

```json theme={null}
{
  "ownerUserId": {
    "operator": "is",
    "values": ["usr_xyz789"]
  }
}
```

Contacts tagged with any of several tags:

```json theme={null}
{
  "tagId": {
    "operator": "include_any_of",
    "values": ["tag_abc", "tag_def"]
  }
}
```

Created in a date range:

```json theme={null}
{
  "createdAt": {
    "operator": "is_between",
    "values": ["2025-01-01T00:00:00.000Z", "2025-01-31T23:59:59.999Z"]
  }
}
```

## Permissions

List results respect the API key user's permissions:

* **Contacts and companies** — If the user cannot view records owned by others, results are limited to records they own.
* **Deals** — If the user cannot view deals owned by others, results include only deals they own or are assigned to.
* **Leads** — If the user cannot view leads owned by others, results include only leads they own or are assigned to.
* **Tasks** — If the user cannot view tasks assigned to others, results include only tasks they created or are assigned to.
* **Quotations** — If the user cannot view quotations owned by others, results include only quotations where they are the sales person (or `salesPersonId` is unset).

## Response

```json theme={null}
{
  "data": [
    {
      "id": "clt_abc123",
      "number": "CON001",
      "firstName": "Jane",
      "lastName": "Smith",
      "email": "jane@example.com",
      "phone": "+971501234567",
      "salutation": "Ms.",
      "jobTitle": "Operations Manager",
      "companyId": "clt_company456",
      "createdAt": "2025-01-15T10:30:00.000Z",
      "cf_industry": "Technology"
    }
  ],
  "meta": {
    "nextCursor": "clt_xyz789",
    "hasMore": true
  }
}
```

Fetch the next page with the cursor:

```bash theme={null}
curl "https://api.heffl.com/api/v2/contacts?cursor=clt_xyz789&pageSize=25" \
  -H "x-api-key: YOUR_API_KEY"
```
