
## Search documents

`GET /v1/note/documents/search`

Runs a full-text search over the titles and contents of documents from knowledge bases available to the key, as well as documents to which direct access has been granted. Use it to find documents by keywords when the identifier is not known in advance.

The generic `filter` parameter is not applied by this endpoint. By default, the API preserves the previous HTTP 200 response and data, adds `Warning: 299 - "filter is not supported on this endpoint and was ignored"`, and records unsupported-filter use in the server log.
The POST form retains its previous behavior.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|---------|
| `query` (query) | string | yes | Search query. Minimum 3 characters, maximum 200 |
| `limit` (query) | integer | no | Number of results, from 1 to 200 |
| `offset` (query) | integer | no | Result offset, from 0 to 10000. Defaults to 0 |

**Next page.** If `meta.hasMore` is `true`, repeat the same `query` and `limit` with the offset increased by the page size: after `limit=20&offset=0`, request `limit=20&offset=20`. Search is capped at offset 10000: if `hasMore` is still `true` there, another search page is unavailable. Use the [document list](/docs/note/documents/list) to traverse all documents.

## Examples

### curl — personal key

```bash
curl -G https://vibecode.bitrix24.com/v1/note/documents/search \
  --data-urlencode "query=contract" \
  --data-urlencode "limit=20" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl -G https://vibecode.bitrix24.com/v1/note/documents/search \
  --data-urlencode "query=contract" \
  --data-urlencode "limit=20" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const params = new URLSearchParams({ query: 'contract', limit: '20' })
const res = await fetch(`https://vibecode.bitrix24.com/v1/note/documents/search?${params}`, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data } = await res.json()
console.log('Found:', data)
```

### JavaScript — OAuth application

```javascript
const params = new URLSearchParams({ query: 'contract', limit: '20' })
const res = await fetch(`https://vibecode.bitrix24.com/v1/note/documents/search?${params}`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})
const { data } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | array | Array of found documents |
| `data[].documentId` | number | Document identifier. Get the document: `GET /v1/note/documents/:id` |
| `data[].collectionId` | number | The document's knowledge base. List: `GET /v1/note/collections` |
| `data[].title` | string | Document title |
| `data[].score` | number | Relevance score of the match |
| `data[].snippet` | string | Document fragment with highlighted matches in HTML |
| `data[].sharedAccess` | boolean | `true` if the document is available via direct access rather than knowledge base membership |
| `meta.hasMore` | boolean | Whether there are more results beyond `limit` |

## Response example

```json
{
  "success": true,
  "data": [
    {
      "documentId": 11,
      "collectionId": 9,
      "title": "Chapter 1",
      "score": 0.0984337329864502,
      "snippet": "<mark>Chapter</mark> 1\nDocument text",
      "sharedAccess": false
    },
    {
      "documentId": 5,
      "collectionId": 7,
      "title": "Chapter 1 (updated)",
      "score": 0.0984337329864502,
      "snippet": "<mark>Chapter</mark> 1\nUpdated text",
      "sharedAccess": false
    }
  ],
  "meta": {
    "hasMore": false
  }
}
```

## Error response example

400 — query shorter than 3 characters:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "`query` must be at least 3 characters"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 200 | `Warning: 299` | The filter is ignored by default; previous data is preserved and the warning is sent in the `Warning` header. |
| 400 (strict mode only) | `UNSUPPORTED_FILTER` | The server mode is disabled by default; until it is enabled, the endpoint preserves HTTP 200 and the previous data. |
| 400 | `INVALID_PARAMS` | `query` is missing or shorter than 3 characters |
| 400 | `INVALID_PARAMS` | `limit` is outside the range from 1 to 200 |
| 400 | `INVALID_PARAMS` | `offset` is not an integer from 0 to 10000 |
| 403 | `SCOPE_DENIED` | The key lacks the `note` scope |
| 401 | `TOKEN_MISSING` | The API key has no tokens configured |

Full list of common API errors — [Errors](/docs/errors).

## Known specifics

**The `snippet` field contains HTML.** The fragment arrives with HTML markup — matches are wrapped in `<mark>…</mark>` tags rather than Markdown. An application that displays `snippet` in its interface must sanitize this HTML by removing unsafe constructs before rendering it. Otherwise, third-party code could be injected into the page through the document contents (XSS).

**POST form of the request.** The endpoint also accepts `POST /v1/note/documents/search` with the same parameters in a JSON body: `{ "query": "contract", "limit": 20, "offset": 20 }`. The response is identical in both forms. The canonical form is GET. If a parameter is passed both in the query string and in the body, the body value takes precedence.

## See also

- [Get a document](/docs/note/documents/get)
- [List documents](/docs/note/documents/list)
- [Document tree](/docs/note/collections/tree)
- [Documents](/docs/note/documents)
