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

# Search Documents

> Search your organization's documents with structured filters and cursor or offset pagination.

## Endpoint

```
POST /core/documents/search
```

## Authentication

This endpoint requires authentication via API key. Include your API key in the `X-API-Key` header:

```bash theme={null}
X-API-Key: ca_your_api_key_here
```

The organization and user context are derived from your API key. You never pass an organization or user identifier in the request body.

## Request Body

All fields are optional. An empty body (`{}`) returns the first page of documents with no filters applied.

| Field             | Type           | Description                                                                                                            |
| ----------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `limit`           | integer        | Maximum number of documents to return. Between `1` and `200`. Defaults to `100`                                        |
| `offset`          | integer        | Number of documents to skip, for offset-based pagination. Must be `>= 0`. Defaults to `0`                              |
| `last_updated_at` | string or null | Cursor for incremental fetching by update time. Pass the `next_cursor` from a previous response to get the next page   |
| `last_created_at` | string or null | Cursor for incremental fetching by creation time. Pass the `next_cursor` from a previous response to get the next page |
| `filters`         | array          | List of filter objects to narrow the results. Defaults to `[]` (no filtering). See [Filter Types](#filter-types)       |

<Warning>
  Pagination modes are mutually exclusive:

  * You may set at most one of `last_updated_at` or `last_created_at`.
  * `offset` cannot be combined with `last_updated_at` or `last_created_at`.

  Violating these rules returns a `422` error. Use `offset`/`limit` for simple paging, or a single cursor for incremental syncs.
</Warning>

### Filter Types

Each entry in `filters` is one of three object types, selected by its `type` field.

#### Field Filter

Filters on a document header field or an org field.

| Field      | Type    | Required | Description                                                                                             |
| ---------- | ------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `type`     | string  | Yes      | Must be `"field"`                                                                                       |
| `field_id` | integer | Yes      | The field to filter on. See reserved header field IDs below; any other ID is treated as an org field ID |
| `operator` | string  | Yes      | Comparison operator. See [Operators](#operators)                                                        |
| `value`    | any     | Yes      | Value to compare against. See [Values](#values)                                                         |

Reserved header field IDs:

| ID  | Field               |
| --- | ------------------- |
| `1` | document type       |
| `2` | document title      |
| `3` | file name           |
| `4` | uploaded by user ID |
| `5` | active              |
| `6` | source              |
| `7` | document created at |
| `8` | exhibits            |
| `9` | category            |

#### Attribute Filter

Filters on a mapped attribute.

| Field          | Type   | Required | Description                                                                  |
| -------------- | ------ | -------- | ---------------------------------------------------------------------------- |
| `type`         | string | Yes      | Must be `"attribute"`                                                        |
| `attribute_id` | string | Yes      | Attribute identifier in the form `<name>_<type>`, e.g. `opportunity_id_text` |
| `operator`     | string | Yes      | Comparison operator. See [Operators](#operators)                             |
| `value`        | any    | Yes      | Value to compare against. See [Values](#values)                              |

#### Group Filter

Combines nested filters with a boolean operator. Groups can be nested recursively.

| Field            | Type   | Required | Description                                                               |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------- |
| `type`           | string | Yes      | Must be `"group"`                                                         |
| `group_operator` | string | No       | How to combine the nested filters: `"and"` or `"or"`. Defaults to `"and"` |
| `filters`        | array  | Yes      | List of nested filter objects (field, attribute, or group)                |

#### Operators

The `operator` field accepts one of: `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `not_in`, `between`, `contains`, `not_contains`, `exists`.

#### Values

The `value` field is either a scalar (string, number, or boolean) or an array of scalars. Use an array for operators that expect multiple values, such as `in`, `not_in`, and `between`.

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://platform.chamelio.ai/core/documents/search" \
    -H "X-API-Key: ca_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "limit": 50,
      "filters": [
        {
          "type": "group",
          "group_operator": "and",
          "filters": [
            {
              "type": "field",
              "field_id": 1,
              "operator": "eq",
              "value": "Master Services Agreement"
            },
            {
              "type": "attribute",
              "attribute_id": "opportunity_id_text",
              "operator": "in",
              "value": ["OPP-1001", "OPP-1002"]
            }
          ]
        }
      ]
    }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://platform.chamelio.ai/core/documents/search"
  headers = {
      "X-API-Key": "ca_your_api_key_here",
      "Content-Type": "application/json"
  }

  payload = {
      "limit": 50,
      "filters": [
          {
              "type": "group",
              "group_operator": "and",
              "filters": [
                  {
                      "type": "field",
                      "field_id": 1,
                      "operator": "eq",
                      "value": "Master Services Agreement"
                  },
                  {
                      "type": "attribute",
                      "attribute_id": "opportunity_id_text",
                      "operator": "in",
                      "value": ["OPP-1001", "OPP-1002"]
                  }
              ]
          }
      ]
  }

  response = requests.post(url, json=payload, headers=headers)
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://platform.chamelio.ai/core/documents/search', {
    method: 'POST',
    headers: {
      'X-API-Key': 'ca_your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      limit: 50,
      filters: [
        {
          type: 'group',
          group_operator: 'and',
          filters: [
            {
              type: 'field',
              field_id: 1,
              operator: 'eq',
              value: 'Master Services Agreement'
            },
            {
              type: 'attribute',
              attribute_id: 'opportunity_id_text',
              operator: 'in',
              value: ['OPP-1001', 'OPP-1002']
            }
          ]
        }
      ]
    })
  });

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

## Response

### Success Response

**Status Code:** `200 OK`

```json theme={null}
{
  "documents": [
    {
      "document_id": 90210,
      "org_id": 42,
      "file_name": "acme_msa.pdf",
      "document_title": "Acme Master Services Agreement",
      "document_type": "Master Services Agreement",
      "summary": "Master services agreement between Acme and Contoso.",
      "fields": [
        {
          "field_name": "Governing Law",
          "field_value_type": "enum",
          "org_field_id": 301,
          "value": "Delaware",
          "is_unclear": false,
          "is_null": false
        }
      ],
      "workflow_metadata": {
        "workflow_state_id": "wfs_abc123xyz",
        "workflow_id": "vendor_contract_review",
        "org_id": 42,
        "user_id": 7,
        "workflow_version": 3,
        "task_id": 12345
      },
      "document_created_at": "2026-05-14T09:30:00Z",
      "mapped_fields": [
        {
          "name": "opportunity_id",
          "field_type": "text",
          "value": "OPP-1001"
        }
      ]
    }
  ],
  "has_next": true,
  "next_cursor": "2026-05-14T09:30:00Z"
}
```

### Response Fields

| Field         | Type           | Description                                                                                                                                      |
| ------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `documents`   | array          | List of matching documents. Each entry is a [Document Object](#document-object)                                                                  |
| `has_next`    | boolean        | Whether more documents are available beyond this page                                                                                            |
| `next_cursor` | string or null | Cursor to fetch the next page. Feed this value back as `last_updated_at` or `last_created_at` (matching the cursor you used) on the next request |

### Document Object

Each object in the `documents` array contains:

| Field                 | Type           | Description                                                                                                            |
| --------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `document_id`         | integer        | Unique identifier of the document                                                                                      |
| `org_id`              | integer        | Identifier of the organization that owns the document                                                                  |
| `file_name`           | string or null | Original file name                                                                                                     |
| `document_title`      | string or null | Human-readable document title                                                                                          |
| `document_type`       | string         | Document type name                                                                                                     |
| `summary`             | string or null | Generated summary of the document                                                                                      |
| `fields`              | array          | Extracted org field values. Each entry is a [Field Value Object](#field-value-object)                                  |
| `workflow_metadata`   | object or null | Workflow context if the document originated from a workflow. See [Workflow Metadata Object](#workflow-metadata-object) |
| `document_created_at` | string or null | Timestamp the document was created                                                                                     |
| `mapped_fields`       | array          | Mapped attribute values. Each entry is a [Mapped Field Object](#mapped-field-object)                                   |

### Field Value Object

| Field              | Type                             | Description                                                                          |
| ------------------ | -------------------------------- | ------------------------------------------------------------------------------------ |
| `field_name`       | string                           | Name of the org field                                                                |
| `field_value_type` | string                           | Value type of the field (e.g. `text`, `enum`, `number`, `boolean`, `date`, `clause`) |
| `org_field_id`     | integer                          | Identifier of the org field                                                          |
| `value`            | string, number, boolean, or null | Extracted value; `null` when unavailable                                             |
| `is_unclear`       | boolean                          | Whether the extracted value is uncertain                                             |
| `is_null`          | boolean                          | Whether the field was explicitly resolved as empty                                   |

### Workflow Metadata Object

| Field               | Type            | Description                                  |
| ------------------- | --------------- | -------------------------------------------- |
| `workflow_state_id` | string          | Internal workflow state identifier           |
| `workflow_id`       | string          | Workflow identifier                          |
| `org_id`            | integer         | Organization identifier                      |
| `user_id`           | integer         | Identifier of the user who ran the workflow  |
| `workflow_version`  | integer or null | Workflow version number                      |
| `task_id`           | integer or null | Task identifier associated with the document |

### Mapped Field Object

| Field        | Type             | Description                                                               |
| ------------ | ---------------- | ------------------------------------------------------------------------- |
| `name`       | string           | Name of the mapped attribute                                              |
| `field_type` | string           | Type of the attribute. One of `text`, `number`, `boolean`, `date`, `link` |
| `value`      | string or number | Value of the mapped attribute                                             |

## Error Responses

### 401 Unauthorized

Returned when authentication fails. See the [authentication errors](/api-reference/api-keys#authentication-errors) section for details.

```json theme={null}
{
  "detail": "Invalid API key"
}
```

### 422 Validation Error

Returned when the request body is invalid - either a local validation failure (such as combining `offset` with a cursor, or setting both cursors) or a filter that the search backend rejects. Filter errors are collected and returned together.

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "filters", 0, "operator"],
      "msg": "unsupported operator",
      "type": "value_error"
    }
  ]
}
```

### 500 Internal Server Error

Returned when the search could not be completed due to a server error.

```json theme={null}
{
  "detail": "Failed to search documents: Internal processing error"
}
```

## Notes

<Info>
  To page through a large result set incrementally, use a single cursor: send the first request with no `offset` or cursor, then pass the returned `next_cursor` as `last_updated_at` (or `last_created_at`) on each subsequent request until `has_next` is `false`.
</Info>

<Tip>
  Use [`GET /core/org-fields`](/api-reference/endpoint/core/org-fields) to look up the `org_field_id` and attribute identifiers you can reference in `field` and `attribute` filters.
</Tip>

## Use Cases

This endpoint is useful for:

* **Document discovery** - Find documents matching specific field or attribute criteria
* **Incremental sync** - Keep an external system up to date by cursoring on `last_updated_at`
* **Reporting** - Retrieve documents by type, status, or mapped attributes for analytics
* **Complex queries** - Combine multiple conditions with nested `and`/`or` group filters
