---
title: "Knowledge"
description: "Every operation in this group: what it accepts, what it returns and the errors it can answer with."
url: "https://openemail.uk/docs/api/reference/knowledge"
area: "API"
category: "Reference"
---

# Knowledge

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

## Operations

The workspace knowledge base: notes, files and web pages the AI uses when it writes replies, drafts email and answers in the assistant. Each item sits at one level. A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.

Files are read into text in the background, PDFs, Office and OpenDocument files, spreadsheets, CSV, HTML, XML, Markdown, text and images among them. Text is encrypted at rest, and search runs over the meaning of the text as well as its words.

### `GET /knowledge`

List knowledge items

Newest first. Every filter is optional. `q` matches titles, file names and links. A key or an app limited to particular addresses sees the whole-workspace items and the items at its addresses and their domains.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Query parameters**

- `scope` (`string`): Only the items at exactly this level. A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, one of `"workspace"`, `"domain"`, `"address"`): Only items at this kind of level.
- `kind` (`string`, one of `"note"`, `"file"`, `"link"`): Keeps one kind of item: `note`, `file` or `link`.
- `status` (`string`, one of `"queued"`, `"processing"`, `"ready"`, `"failed"`): Keeps one status: `queued`, `processing`, `ready` or `failed`.
- `pinned` (`string`, one of `"true"`, `"false"`): `true` keeps the pinned notes and `false` everything else.
- `q` (`string`): Words in the title, file name or link.
- `limit` (`integer`, at least 1, at most 100, default `25`): Rows per page, 1 to 100.
- `cursor` (`string`): The previous page's `nextCursor`, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 `invalid_cursor`.

**Returns**

- `200` `KnowledgeItemList`: A page of items.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.list()`](https://openemail.uk/docs/sdk/reference/knowledge#list), [`knowledge.listAll()`](https://openemail.uk/docs/sdk/reference/knowledge#listAll), [`knowledge.iterate()`](https://openemail.uk/docs/sdk/reference/knowledge#iterate); Python [`knowledge.list()`](https://openemail.uk/docs/python/reference/knowledge#list), [`knowledge.list_all()`](https://openemail.uk/docs/python/reference/knowledge#listAll), [`knowledge.iterate()`](https://openemail.uk/docs/python/reference/knowledge#iterate); Ruby [`knowledge.list`](https://openemail.uk/docs/ruby/reference/knowledge#list), [`knowledge.list_all`](https://openemail.uk/docs/ruby/reference/knowledge#listAll), [`knowledge.iterate`](https://openemail.uk/docs/ruby/reference/knowledge#iterate); PHP [`knowledge->list`](https://openemail.uk/docs/php/reference/knowledge#list), [`knowledge->listAll`](https://openemail.uk/docs/php/reference/knowledge#listAll), [`knowledge->iterate`](https://openemail.uk/docs/php/reference/knowledge#iterate); CLI [`openemail knowledge list`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list); MCP [`listKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#listKnowledge).

### `GET /knowledge/levels`

List knowledge levels

The whole workspace, each domain and each address the caller can see, how many items each holds and whether the caller may change items there.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Returns**

- `200` `KnowledgeLevelList`: Every level the caller can see.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.levels()`](https://openemail.uk/docs/sdk/reference/knowledge#levels); Python [`knowledge.levels()`](https://openemail.uk/docs/python/reference/knowledge#levels); Ruby [`knowledge.levels`](https://openemail.uk/docs/ruby/reference/knowledge#levels); PHP [`knowledge->levels`](https://openemail.uk/docs/php/reference/knowledge#levels); CLI [`openemail knowledge levels`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-levels); MCP [`listKnowledgeLevels`](https://openemail.uk/docs/mcp/tools/knowledge#listKnowledgeLevels).

### `GET /knowledge/usage`

Read knowledge base usage

How many items and characters of text the workspace holds, against what its plan allows.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Returns**

- `200` `KnowledgeUsage`: The usage and the limits.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.usage()`](https://openemail.uk/docs/sdk/reference/knowledge#usage); Python [`knowledge.usage()`](https://openemail.uk/docs/python/reference/knowledge#usage); Ruby [`knowledge.usage`](https://openemail.uk/docs/ruby/reference/knowledge#usage); PHP [`knowledge->usage`](https://openemail.uk/docs/php/reference/knowledge#usage); CLI [`openemail knowledge usage`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-usage); MCP [`getKnowledgeUsage`](https://openemail.uk/docs/mcp/tools/knowledge#getKnowledgeUsage).

### `POST /knowledge/search`

Search the knowledge base

The passages that best answer `query`, by meaning and by words, the way the AI finds them. With `address`, the levels the AI uses for that address: the address, its domain and the whole workspace, the most specific ranked a little higher. With `scope`, that one level. With neither, every level the caller can see.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Request body**

- `query` (`string`, required, 1 to 500 characters): What to look for, in plain words, up to 500 characters.
- `address` (`string`, up to 320 characters): An address of the workspace, to search the levels the AI uses when it writes as that address.
- `scope` (`string`, up to 320 characters): One level to search: an empty string for the whole workspace, `@` and a domain, or one address.
- `limit` (`integer`, at least 1, at most 25): How many passages, from 1 to 25. The server defaults to 8.
- `rerank` (`boolean`): When true, the AI reads the best 25 passages and puts them in the order that best answers `query`, leaving out the ones that do not help. It adds a second or two and counts as one AI action. When it cannot finish, the passages keep their usual order and `reranked` is false.

**Returns**

- `200` `KnowledgeSearchResult`: The passages, best first.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.search()`](https://openemail.uk/docs/sdk/reference/knowledge#search); Python [`knowledge.search()`](https://openemail.uk/docs/python/reference/knowledge#search); Ruby [`knowledge.search`](https://openemail.uk/docs/ruby/reference/knowledge#search); PHP [`knowledge->search`](https://openemail.uk/docs/php/reference/knowledge#search); CLI [`openemail knowledge search`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-search); MCP [`searchKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#searchKnowledge).

### `POST /knowledge/notes`

Add a note

Up to 20,000 characters of text, in Markdown if you like. A note is usually ready for the AI in a second or two. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Request body**

- `scope` (`string`, up to 320 characters, default `""`): The level: an empty string, or left out, for the whole workspace, `@` and a domain such as `@acme.com`, or one address such as `sales@acme.com`.
- `title` (`string`, required, 1 to 200 characters): A short name for the note, at most 200 characters.
- `body` (`string`, required, 1 to 20000 characters): The text, up to 20,000 characters, in Markdown if you like.
- `pinned` (`boolean`): Puts the note into every prompt at its level. Left out, false.
- `threadId` (`string`, 1 to 200 characters): The conversation the note comes from, such as one `POST /knowledge/drafts` drafted it from.

**Returns**

- `201` `KnowledgeItem`: The note.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.createNote()`](https://openemail.uk/docs/sdk/reference/knowledge#createNote); Python [`knowledge.create_note()`](https://openemail.uk/docs/python/reference/knowledge#createNote); Ruby [`knowledge.create_note`](https://openemail.uk/docs/ruby/reference/knowledge#createNote); PHP [`knowledge->createNote`](https://openemail.uk/docs/php/reference/knowledge#createNote); CLI [`openemail knowledge create-note`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-create-note); MCP [`addKnowledgeNote`](https://openemail.uk/docs/mcp/tools/knowledge#addKnowledgeNote).

### `POST /knowledge/links`

Add a link

A public web page, at most 2048 characters long. It is fetched and read in the background, so the item starts `queued`. Without a `title`, the page's own title is used. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Request body**

- `scope` (`string`, up to 320 characters, default `""`): The level: an empty string, or left out, for the whole workspace, `@` and a domain such as `@acme.com`, or one address such as `sales@acme.com`.
- `url` (`string`, required, 1 to 2048 characters): The page, a public `http` or `https` address of at most 2,048 characters.
- `title` (`string`, up to 200 characters): A name for the item, at most 200 characters. Left out, the page's own title once it has been read.
- `refreshDays` (`integer`, nullable, more than 0): Read the page again every this many days (1, 7, 30), so changes reach the AI on their own. Left out or null, it is read again only when you ask.

**Returns**

- `201` `KnowledgeItem`: The link, queued to be read.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.addLink()`](https://openemail.uk/docs/sdk/reference/knowledge#addLink); Python [`knowledge.add_link()`](https://openemail.uk/docs/python/reference/knowledge#addLink); Ruby [`knowledge.add_link`](https://openemail.uk/docs/ruby/reference/knowledge#addLink); PHP [`knowledge->addLink`](https://openemail.uk/docs/php/reference/knowledge#addLink); CLI [`openemail knowledge add-link`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-add-link); MCP [`addKnowledgeLink`](https://openemail.uk/docs/mcp/tools/knowledge#addKnowledgeLink).

### `POST /knowledge/files`

Upload a file

Send the file itself as the request body, with its `Content-Type`, and name it with `filename` or an `X-Filename` header. At most 20 MB for a document and 10 MB for an image. The text is read in the background, so the item starts `queued`. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Query parameters**

- `scope` (`string`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `filename` (`string`): The file name. Its extension tells the kind of file when the `Content-Type` is generic.
- `title` (`string`, up to 200 characters): Left out, the file name without its extension.

**Request body**

Content type: `application/octet-stream`.

`binary`

**Returns**

- `201` `KnowledgeItem`: The file, queued to be read.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.uploadFile()`](https://openemail.uk/docs/sdk/reference/knowledge#uploadFile); Python [`knowledge.upload_file()`](https://openemail.uk/docs/python/reference/knowledge#uploadFile); Ruby [`knowledge.upload_file`](https://openemail.uk/docs/ruby/reference/knowledge#uploadFile); PHP [`knowledge->uploadFile`](https://openemail.uk/docs/php/reference/knowledge#uploadFile); CLI [`openemail knowledge upload-file`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-upload-file).

### `GET /knowledge/{id}`

Get a knowledge item

The item with its text: a note's body, or the first 20,000 characters read from a file or a page.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Path parameters**

- `id` (`string`, required): The id of a knowledge item, as `GET /knowledge` returns it.

**Returns**

- `200` `KnowledgeItemDetail`: The item and its text.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.get()`](https://openemail.uk/docs/sdk/reference/knowledge#get); Python [`knowledge.get()`](https://openemail.uk/docs/python/reference/knowledge#get); Ruby [`knowledge.get`](https://openemail.uk/docs/ruby/reference/knowledge#get); PHP [`knowledge->get`](https://openemail.uk/docs/php/reference/knowledge#get); CLI [`openemail knowledge get`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-get); MCP [`getKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#getKnowledge).

### `PATCH /knowledge/{id}`

Change a knowledge item

Give at least one field. `body` and `pinned` are for notes, `url` and `refreshDays` are for links. A changed title, body or link is indexed again, and an item moved to another level keeps its index. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole. Moving an item needs that reach at both levels.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a knowledge item, as `GET /knowledge` returns it.

**Request body**

- `title` (`string`, 1 to 200 characters): A new name, at most 200 characters.
- `body` (`string`, 1 to 20000 characters): Notes only.
- `scope` (`string`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `pinned` (`boolean`): Notes only.
- `url` (`string`, 1 to 2048 characters): Links only.
- `refreshDays` (`integer`, nullable, one of `1`, `7`, `30`): Links only: read the page again every this many days. Null stops that.

**Returns**

- `200` `KnowledgeItem`: The item as it is now.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.update()`](https://openemail.uk/docs/sdk/reference/knowledge#update); Python [`knowledge.update()`](https://openemail.uk/docs/python/reference/knowledge#update); Ruby [`knowledge.update`](https://openemail.uk/docs/ruby/reference/knowledge#update); PHP [`knowledge->update`](https://openemail.uk/docs/php/reference/knowledge#update); CLI [`openemail knowledge update`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-update); MCP [`updateKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#updateKnowledge).

### `DELETE /knowledge/{id}`

Delete a knowledge item

Gone for good, with its file and its passages. The AI stops using it at once.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a knowledge item, as `GET /knowledge` returns it.

**Returns**

- `200` `DeletedKnowledgeItem`: Deleted.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.delete()`](https://openemail.uk/docs/sdk/reference/knowledge#delete); Python [`knowledge.delete()`](https://openemail.uk/docs/python/reference/knowledge#delete); Ruby [`knowledge.delete`](https://openemail.uk/docs/ruby/reference/knowledge#delete); PHP [`knowledge->delete`](https://openemail.uk/docs/php/reference/knowledge#delete); CLI [`openemail knowledge delete`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-delete); MCP [`deleteKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#deleteKnowledge).

### `POST /knowledge/{id}/refresh`

Read a knowledge item again

Fetches a link again, reads a file again, or indexes a note again, and clears a failure. The previous text stays in use until the new one is ready.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a knowledge item, as `GET /knowledge` returns it.

**Returns**

- `200` `KnowledgeItem`: The item, queued to be read again.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.refresh()`](https://openemail.uk/docs/sdk/reference/knowledge#refresh); Python [`knowledge.refresh()`](https://openemail.uk/docs/python/reference/knowledge#refresh); Ruby [`knowledge.refresh`](https://openemail.uk/docs/ruby/reference/knowledge#refresh); PHP [`knowledge->refresh`](https://openemail.uk/docs/php/reference/knowledge#refresh); CLI [`openemail knowledge refresh`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-refresh); MCP [`refreshKnowledge`](https://openemail.uk/docs/mcp/tools/knowledge#refreshKnowledge).

### `GET /knowledge/stats`

Read knowledge base stats

How the AI used the knowledge base over the last `days` days, 30 unless you say. `uses` counts the times a reply suggestion, a draft, the assistant or a search found something in it and `empty` the times it looked and found nothing, for the whole workspace, with `bySurface` splitting `uses` by where. `topItems`, `unusedItems`, the waiting suggestions and questions and the open flags count only what the caller can see.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Query parameters**

- `days` (`integer`, at least 1, at most 90, default `30`): How many days back to count, today included.

**Returns**

- `200` `KnowledgeStats`: The stats.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.stats()`](https://openemail.uk/docs/sdk/reference/knowledge#stats); Python [`knowledge.stats()`](https://openemail.uk/docs/python/reference/knowledge#stats); Ruby [`knowledge.stats`](https://openemail.uk/docs/ruby/reference/knowledge#stats); PHP [`knowledge->stats`](https://openemail.uk/docs/php/reference/knowledge#stats); CLI [`openemail knowledge stats`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-stats); MCP [`getKnowledgeStats`](https://openemail.uk/docs/mcp/tools/knowledge#getKnowledgeStats).

### `GET /knowledge/suggestions`

List knowledge suggestions

Notes the AI suggests and questions nothing in the knowledge base answers, the most recent first, pending ones unless you ask for another `status`. A `learned` suggestion comes from a reply sent from the workspace in a conversation: the AI reads the message the reply answers and the reply, and keeps up to three facts that would hold for other people too, at the level of the domain the reply was sent from, or the whole workspace when that domain is not one of its own. Facts the knowledge base already holds are left out, and at most 100 replies a day are read. A `question` comes from an incoming message: when the AI suggests replies to it, it notes up to 3 things the sender asked about the business that neither the conversation nor the knowledge base answers, at the level of the domain the message arrived at, chosen the same way. The same fact or question again counts up `occurrences`, and one that was dismissed is not suggested again. Both stop while the workspace setting `knowledgeLearning` is off.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Query parameters**

- `kind` (`string`, one of `"learned"`, `"question"`): Keeps one kind: `learned` for notes drawn from sent replies, or `question` for questions nothing answers.
- `status` (`string`, one of `"pending"`, `"accepted"`, `"dismissed"`, default `"pending"`): Keeps one status: `pending`, `accepted` or `dismissed`. Left out, `pending`.
- `limit` (`integer`, at least 1, at most 100, default `25`): Rows per page, 1 to 100.
- `cursor` (`string`): The previous page's `nextCursor`, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 `invalid_cursor`.

**Returns**

- `200` `KnowledgeSuggestionList`: A page of suggestions and questions.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.listSuggestions()`](https://openemail.uk/docs/sdk/reference/knowledge#listSuggestions), [`knowledge.listAllSuggestions()`](https://openemail.uk/docs/sdk/reference/knowledge#listAllSuggestions), [`knowledge.iterateSuggestions()`](https://openemail.uk/docs/sdk/reference/knowledge#iterateSuggestions); Python [`knowledge.list_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#listSuggestions), [`knowledge.list_all_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#listAllSuggestions), [`knowledge.iterate_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#iterateSuggestions); Ruby [`knowledge.list_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#listSuggestions), [`knowledge.list_all_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#listAllSuggestions), [`knowledge.iterate_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#iterateSuggestions); PHP [`knowledge->listSuggestions`](https://openemail.uk/docs/php/reference/knowledge#listSuggestions), [`knowledge->listAllSuggestions`](https://openemail.uk/docs/php/reference/knowledge#listAllSuggestions), [`knowledge->iterateSuggestions`](https://openemail.uk/docs/php/reference/knowledge#iterateSuggestions); CLI [`openemail knowledge list-suggestions`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list-suggestions); MCP [`listKnowledgeSuggestions`](https://openemail.uk/docs/mcp/tools/knowledge#listKnowledgeSuggestions).

### `POST /knowledge/suggestions/{id}/accept`

Accept a knowledge suggestion

Saves the suggestion as a note, with any field you send in place of the suggested one, and marks it accepted. A question needs its answer in `body`, and its title stays the question unless you send one. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a suggestion or question, as `GET /knowledge/suggestions` returns it.

**Request body**

- `title` (`string`, 1 to 200 characters): Left out, the suggested title or the question.
- `body` (`string`, 1 to 20000 characters): Left out, the suggested note. A question needs it: the answer.
- `scope` (`string`): Left out, the suggested level. A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `pinned` (`boolean`): Put the note into every prompt at its level.

**Returns**

- `200` `KnowledgeSuggestionAccepted`: The suggestion and the note made from it.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.acceptSuggestion()`](https://openemail.uk/docs/sdk/reference/knowledge#acceptSuggestion); Python [`knowledge.accept_suggestion()`](https://openemail.uk/docs/python/reference/knowledge#acceptSuggestion); Ruby [`knowledge.accept_suggestion`](https://openemail.uk/docs/ruby/reference/knowledge#acceptSuggestion); PHP [`knowledge->acceptSuggestion`](https://openemail.uk/docs/php/reference/knowledge#acceptSuggestion); CLI [`openemail knowledge accept-suggestion`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-accept-suggestion); MCP [`acceptKnowledgeSuggestion`](https://openemail.uk/docs/mcp/tools/knowledge#acceptKnowledgeSuggestion).

### `POST /knowledge/suggestions/{id}/dismiss`

Dismiss a knowledge suggestion

Marks the suggestion or question dismissed, so it leaves the pending list and is not suggested again. Nothing is added to the knowledge base. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a suggestion or question, as `GET /knowledge/suggestions` returns it.

**Returns**

- `200` `KnowledgeSuggestion`: The suggestion, dismissed.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.dismissSuggestion()`](https://openemail.uk/docs/sdk/reference/knowledge#dismissSuggestion); Python [`knowledge.dismiss_suggestion()`](https://openemail.uk/docs/python/reference/knowledge#dismissSuggestion); Ruby [`knowledge.dismiss_suggestion`](https://openemail.uk/docs/ruby/reference/knowledge#dismissSuggestion); PHP [`knowledge->dismissSuggestion`](https://openemail.uk/docs/php/reference/knowledge#dismissSuggestion); CLI [`openemail knowledge dismiss-suggestion`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-dismiss-suggestion); MCP [`dismissKnowledgeSuggestion`](https://openemail.uk/docs/mcp/tools/knowledge#dismissKnowledgeSuggestion).

### `GET /knowledge/flags`

List knowledge flags

Open warnings about pairs of items, newest first. Each item is compared with the closest items at every level when it is indexed, and again whenever it changes. `duplicate` means two items say nearly the same thing. `conflict` means the AI found that two closely related items disagree on a fact, such as a price or a deadline, and `detail` says how. Conflicts are looked for while the workspace setting `knowledgeLearning` is on, at most 200 times a day. A flag shows only to a caller who can see both items. With `itemId`, only the flags that name that item.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Query parameters**

- `itemId` (`string`): Only the flags that name this knowledge item.
- `limit` (`integer`, at least 1, at most 100, default `50`): How many flags, from 1 to 100. The server defaults to 50.

**Returns**

- `200` `KnowledgeFlagList`: The open flags.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.listFlags()`](https://openemail.uk/docs/sdk/reference/knowledge#listFlags); Python [`knowledge.list_flags()`](https://openemail.uk/docs/python/reference/knowledge#listFlags); Ruby [`knowledge.list_flags`](https://openemail.uk/docs/ruby/reference/knowledge#listFlags); PHP [`knowledge->listFlags`](https://openemail.uk/docs/php/reference/knowledge#listFlags); CLI [`openemail knowledge list-flags`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list-flags); MCP [`listKnowledgeFlags`](https://openemail.uk/docs/mcp/tools/knowledge#listKnowledgeFlags).

### `POST /knowledge/flags/{id}/dismiss`

Dismiss a knowledge flag

Marks the flag dismissed, and the same two items are not flagged for the same reason again. To settle a real duplicate or conflict instead, change or delete one of the items. It needs the reach to change items at the levels of both.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a flag, as `GET /knowledge/flags` returns it.

**Returns**

- `200` `KnowledgeFlag`: The flag, dismissed.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.dismissFlag()`](https://openemail.uk/docs/sdk/reference/knowledge#dismissFlag); Python [`knowledge.dismiss_flag()`](https://openemail.uk/docs/python/reference/knowledge#dismissFlag); Ruby [`knowledge.dismiss_flag`](https://openemail.uk/docs/ruby/reference/knowledge#dismissFlag); PHP [`knowledge->dismissFlag`](https://openemail.uk/docs/php/reference/knowledge#dismissFlag); CLI [`openemail knowledge dismiss-flag`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-dismiss-flag); MCP [`dismissKnowledgeFlag`](https://openemail.uk/docs/mcp/tools/knowledge#dismissKnowledgeFlag).

### `GET /knowledge/connectors`

List knowledge connectors

Every connector at a level the caller can see, newest first.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Returns**

- `200` `KnowledgeConnectorList`: The connectors.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.listConnectors()`](https://openemail.uk/docs/sdk/reference/knowledge#listConnectors); Python [`knowledge.list_connectors()`](https://openemail.uk/docs/python/reference/knowledge#listConnectors); Ruby [`knowledge.list_connectors`](https://openemail.uk/docs/ruby/reference/knowledge#listConnectors); PHP [`knowledge->listConnectors`](https://openemail.uk/docs/php/reference/knowledge#listConnectors); CLI [`openemail knowledge list-connectors`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list-connectors); MCP [`listKnowledgeConnectors`](https://openemail.uk/docs/mcp/tools/knowledge#listKnowledgeConnectors).

### `POST /knowledge/connectors`

Add a knowledge connector

Keeps many web pages from one source in the knowledge base, each page as a link item at the connector's level. `site` reads the page at `url` and follows its links to pages on the same host under the same path, leaving out what the site's robots.txt disallows. `sitemap` reads a sitemap, or a sitemap index and up to 5 of its sitemaps. `feed` reads an RSS or Atom feed. `zendesk` reads the published articles of a Zendesk help center, from its address such as https://example.zendesk.com. It keeps at most `pageLimit` pages, 25 unless you say. The first sync starts within a minute, and it syncs again every `refreshDays` days, 7 unless you say: new pages are added, changed ones are read again and pages that are gone are removed. A page already in the knowledge base as a link at the same level is left to that item. Its items count toward the plan allowance, and a sync stops adding pages once that is reached. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Request body**

- `kind` (`string`, required, one of `"site"`, `"sitemap"`, `"feed"`, `"zendesk"`): A site it crawls, a sitemap, an RSS or Atom feed, or a Zendesk help center.
- `url` (`string`, required, 1 to 2048 characters): A public https address: the page a site crawl starts from, the sitemap, the feed, or the address of the help center.
- `scope` (`string`, default `""`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `title` (`string`, up to 200 characters): Left out, the host and the kind.
- `refreshDays` (`integer`, nullable, one of `1`, `7`, `30`): Sync again every this many days, 7 when left out. Null syncs only when you ask.
- `pageLimit` (`integer`, at least 1, at most 200, default `25`): The most pages to keep.

**Returns**

- `201` `KnowledgeConnector`: The connector, queued for its first sync.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.addConnector()`](https://openemail.uk/docs/sdk/reference/knowledge#addConnector); Python [`knowledge.add_connector()`](https://openemail.uk/docs/python/reference/knowledge#addConnector); Ruby [`knowledge.add_connector`](https://openemail.uk/docs/ruby/reference/knowledge#addConnector); PHP [`knowledge->addConnector`](https://openemail.uk/docs/php/reference/knowledge#addConnector); CLI [`openemail knowledge add-connector`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-add-connector); MCP [`addKnowledgeConnector`](https://openemail.uk/docs/mcp/tools/knowledge#addKnowledgeConnector).

### `GET /knowledge/connectors/{id}`

Get a knowledge connector

The connector, how many items it keeps and when it syncs next.

Requires the `knowledge:read` scope.

- Scopes: `knowledge:read`.

**Path parameters**

- `id` (`string`, required): The id of a connector, as `GET /knowledge/connectors` returns it.

**Returns**

- `200` `KnowledgeConnector`: The connector.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.getConnector()`](https://openemail.uk/docs/sdk/reference/knowledge#getConnector); Python [`knowledge.get_connector()`](https://openemail.uk/docs/python/reference/knowledge#getConnector); Ruby [`knowledge.get_connector`](https://openemail.uk/docs/ruby/reference/knowledge#getConnector); PHP [`knowledge->getConnector`](https://openemail.uk/docs/php/reference/knowledge#getConnector); CLI [`openemail knowledge get-connector`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-get-connector); MCP [`getKnowledgeConnector`](https://openemail.uk/docs/mcp/tools/knowledge#getKnowledgeConnector).

### `PATCH /knowledge/connectors/{id}`

Change a knowledge connector

Give at least one field. Moving it to another level moves its items with it, and they are indexed again there. Changing an item needs reach over every address its level covers: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address. A key or an app limited to particular addresses can change items only at those addresses, or at domains it holds whole. Moving it needs that reach at both levels.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a connector, as `GET /knowledge/connectors` returns it.

**Request body**

- `title` (`string`, 1 to 200 characters): A new name, at most 200 characters.
- `scope` (`string`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `refreshDays` (`integer`, nullable, one of `1`, `7`, `30`): Sync again every this many days. Null syncs only when you ask.
- `pageLimit` (`integer`, at least 1, at most 200): The most pages to keep, from 1 to 200.

**Returns**

- `200` `KnowledgeConnector`: The connector as it is now.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.updateConnector()`](https://openemail.uk/docs/sdk/reference/knowledge#updateConnector); Python [`knowledge.update_connector()`](https://openemail.uk/docs/python/reference/knowledge#updateConnector); Ruby [`knowledge.update_connector`](https://openemail.uk/docs/ruby/reference/knowledge#updateConnector); PHP [`knowledge->updateConnector`](https://openemail.uk/docs/php/reference/knowledge#updateConnector); CLI [`openemail knowledge update-connector`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-update-connector); MCP [`updateKnowledgeConnector`](https://openemail.uk/docs/mcp/tools/knowledge#updateKnowledgeConnector).

### `DELETE /knowledge/connectors/{id}`

Delete a knowledge connector

Gone for good, with every item it added to the knowledge base. The AI stops using them at once.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a connector, as `GET /knowledge/connectors` returns it.

**Returns**

- `200` `DeletedKnowledgeConnector`: Deleted.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.deleteConnector()`](https://openemail.uk/docs/sdk/reference/knowledge#deleteConnector); Python [`knowledge.delete_connector()`](https://openemail.uk/docs/python/reference/knowledge#deleteConnector); Ruby [`knowledge.delete_connector`](https://openemail.uk/docs/ruby/reference/knowledge#deleteConnector); PHP [`knowledge->deleteConnector`](https://openemail.uk/docs/php/reference/knowledge#deleteConnector); CLI [`openemail knowledge delete-connector`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-delete-connector); MCP [`deleteKnowledgeConnector`](https://openemail.uk/docs/mcp/tools/knowledge#deleteKnowledgeConnector).

### `POST /knowledge/connectors/{id}/sync`

Sync a knowledge connector now

Queues a sync that starts within a minute, whatever the schedule says, and clears a failure.

Requires the `knowledge:write` scope.

- Scopes: `knowledge:write`.

**Path parameters**

- `id` (`string`, required): The id of a connector, as `GET /knowledge/connectors` returns it.

**Returns**

- `200` `KnowledgeConnector`: The connector, queued to sync.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.syncConnector()`](https://openemail.uk/docs/sdk/reference/knowledge#syncConnector); Python [`knowledge.sync_connector()`](https://openemail.uk/docs/python/reference/knowledge#syncConnector); Ruby [`knowledge.sync_connector`](https://openemail.uk/docs/ruby/reference/knowledge#syncConnector); PHP [`knowledge->syncConnector`](https://openemail.uk/docs/php/reference/knowledge#syncConnector); CLI [`openemail knowledge sync-connector`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-sync-connector); MCP [`syncKnowledgeConnector`](https://openemail.uk/docs/mcp/tools/knowledge#syncKnowledgeConnector).

### `POST /knowledge/drafts`

Draft a note from a conversation

The AI reads the conversation and writes one note of the facts in it that the team will need again, leaving out personal details and what matters only to that conversation. Nothing is saved: send the draft, changed as you like, to `POST /knowledge/notes` with the same `threadId` to keep it. `scope` suggests a level: the domain the conversation arrived at when the caller may add items there, otherwise the whole workspace or the address. It counts as one AI action.

Requires the `knowledge:write` and `threads:read` scopes.

- Scopes: `knowledge:write`, `threads:read`.

**Request body**

- `threadId` (`string`, required, 1 to 200 characters): The conversation, by the id the thread endpoints give it.

**Returns**

- `200` `KnowledgeDraft`: The draft note.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: TypeScript [`knowledge.draftFromThread()`](https://openemail.uk/docs/sdk/reference/knowledge#draftFromThread); Python [`knowledge.draft_from_thread()`](https://openemail.uk/docs/python/reference/knowledge#draftFromThread); Ruby [`knowledge.draft_from_thread`](https://openemail.uk/docs/ruby/reference/knowledge#draftFromThread); PHP [`knowledge->draftFromThread`](https://openemail.uk/docs/php/reference/knowledge#draftFromThread); CLI [`openemail knowledge draft-from-thread`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-draft-from-thread); MCP [`draftKnowledgeFromThread`](https://openemail.uk/docs/mcp/tools/knowledge#draftKnowledgeFromThread).

### Objects

#### `DeletedKnowledgeConnector`

`object`

- `object` (`string`, one of `"knowledge_connector"`)
- `id` (`string`)
- `deleted` (`boolean`, one of `true`)

#### `DeletedKnowledgeItem`

`object`

- `object` (`string`, one of `"knowledge_item"`)
- `id` (`string`)
- `deleted` (`boolean`, one of `true`)

#### `KnowledgeConnector`

`object`

- `object` (`string`, required, one of `"knowledge_connector"`)
- `id` (`string`, required)
- `kind` (`string`, required, one of `"site"`, `"sitemap"`, `"feed"`, `"zendesk"`): A site it crawls, a sitemap, an RSS or Atom feed, or a Zendesk help center.
- `scope` (`string`, required): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, required, one of `"workspace"`, `"domain"`, `"address"`)
- `title` (`string`, required, up to 200 characters)
- `url` (`string`, required)
- `refreshDays` (`integer`, required, nullable, one of `1`, `7`, `30`): It syncs again every this many days. Null when it syncs only when you ask.
- `pageLimit` (`integer`, required): The most pages it keeps.
- `status` (`string`, required, one of `"queued"`, `"syncing"`, `"ready"`, `"failed"`): `queued` until a sync starts, `syncing` while it reads the source, `ready` once its pages are items, `failed` when the source could not be read after several tries.
- `failure` (`string`, required, nullable, one of `"unsupported"`, `"empty"`, `"too_large"`, `"fetch_failed"`, `"blocked_url"`, `"conversion_failed"`, `"index_failed"`, `"over_allowance"`, `"missing_file"`)
- `items` (`integer`, required): How many items it keeps in the knowledge base.
- `lastSyncAt` (`string`, required, nullable, format `date-time`)
- `nextSyncAt` (`string`, required, nullable, format `date-time`)
- `createdAt` (`string`, required, format `date-time`)
- `updatedAt` (`string`, required, format `date-time`)

#### `KnowledgeConnectorList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`KnowledgeConnector[]`)

#### `KnowledgeDraft`

`object`

- `object` (`string`, required, one of `"knowledge_draft"`)
- `title` (`string`, required)
- `body` (`string`, required): The note, in Markdown.
- `scope` (`string`, required): The suggested level. A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `threadId` (`string`, required)

#### `KnowledgeFlag`

`object`

- `object` (`string`, required, one of `"knowledge_flag"`)
- `id` (`string`, required)
- `kind` (`string`, required, one of `"duplicate"`, `"conflict"`): `duplicate` when the two items say nearly the same thing, `conflict` when they disagree on a fact.
- `status` (`string`, required, one of `"open"`, `"dismissed"`)
- `sourceId` (`string`, required)
- `sourceTitle` (`string`, required)
- `otherSourceId` (`string`, required)
- `otherSourceTitle` (`string`, required)
- `detail` (`string`, required, nullable): For a conflict, one sentence on the facts that disagree. Null for a duplicate.
- `score` (`number`, required): How close in meaning the two items are, from 0 to 1.
- `createdAt` (`string`, required, format `date-time`)

#### `KnowledgeFlagList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`KnowledgeFlag[]`)

#### `KnowledgeItem`

`object`

- `object` (`string`, required, one of `"knowledge_item"`)
- `id` (`string`, required)
- `kind` (`string`, required, one of `"note"`, `"file"`, `"link"`): A note written in place, an uploaded file, or a web page fetched from a link.
- `scope` (`string`, required): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, required, one of `"workspace"`, `"domain"`, `"address"`)
- `title` (`string`, required, up to 200 characters)
- `url` (`string`, required, nullable): The page a link item reads. Null for notes and files.
- `fileName` (`string`, required, nullable)
- `mimeType` (`string`, required, nullable)
- `sizeBytes` (`integer`, required, nullable)
- `pinned` (`boolean`, required): A pinned note goes into every AI prompt at its level, not only when it matches.
- `status` (`string`, required, one of `"queued"`, `"processing"`, `"ready"`, `"failed"`): `queued` and `processing` while the text is read and indexed, `ready` once the AI can use it, `failed` when it could not be read. A changed item goes back to `queued`, and its previous text stays in use until the new one is ready.
- `failure` (`string`, required, nullable, one of `"unsupported"`, `"empty"`, `"too_large"`, `"fetch_failed"`, `"blocked_url"`, `"conversion_failed"`, `"index_failed"`, `"over_allowance"`, `"missing_file"`)
- `chunks` (`integer`, required): How many passages the text was split into for search.
- `chars` (`integer`, required): Characters of text, which count toward the plan allowance.
- `origin` (`string`, required, one of `"app"`, `"api"`, `"assistant"`, `"mcp"`)
- `createdBy` (`string`, required, nullable)
- `createdAt` (`string`, required, format `date-time`)
- `updatedAt` (`string`, required, format `date-time`)
- `indexedAt` (`string`, required, nullable, format `date-time`)
- `refreshDays` (`integer`, required, nullable, one of `1`, `7`, `30`): Links only: the page is read again every this many days, and changes reach the AI on their own. Null when it is read only when you ask.
- `nextRefreshAt` (`string`, required, nullable, format `date-time`): When the page is next read again. Null when it is not scheduled.
- `connectorId` (`string`, required, nullable): The connector that keeps this item in step with its source, or null for an item added by hand.
- `threadId` (`string`, required, nullable): The conversation the note was saved from, or null.
- `uses` (`integer`, required): How many times it came up in a reply suggestion, a draft, the assistant or a search.
- `lastUsedAt` (`string`, required, nullable, format `date-time`)
- `flags` (`integer`, required): How many open duplicate or conflict flags name it. Lists and `GET /knowledge/{id}` count them, and the answer to a change says 0.

#### `KnowledgeItemDetail`

`object`

- `object` (`string`, one of `"knowledge_item"`)
- `id` (`string`)
- `kind` (`string`, one of `"note"`, `"file"`, `"link"`): A note written in place, an uploaded file, or a web page fetched from a link.
- `scope` (`string`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, one of `"workspace"`, `"domain"`, `"address"`)
- `title` (`string`, up to 200 characters)
- `url` (`string`, nullable): The page a link item reads. Null for notes and files.
- `fileName` (`string`, nullable)
- `mimeType` (`string`, nullable)
- `sizeBytes` (`integer`, nullable)
- `pinned` (`boolean`): A pinned note goes into every AI prompt at its level, not only when it matches.
- `status` (`string`, one of `"queued"`, `"processing"`, `"ready"`, `"failed"`): `queued` and `processing` while the text is read and indexed, `ready` once the AI can use it, `failed` when it could not be read. A changed item goes back to `queued`, and its previous text stays in use until the new one is ready.
- `failure` (`string`, nullable, one of `"unsupported"`, `"empty"`, `"too_large"`, `"fetch_failed"`, `"blocked_url"`, `"conversion_failed"`, `"index_failed"`, `"over_allowance"`, `"missing_file"`)
- `chunks` (`integer`): How many passages the text was split into for search.
- `chars` (`integer`): Characters of text, which count toward the plan allowance.
- `origin` (`string`, one of `"app"`, `"api"`, `"assistant"`, `"mcp"`)
- `createdBy` (`string`, nullable)
- `createdAt` (`string`, format `date-time`)
- `updatedAt` (`string`, format `date-time`)
- `indexedAt` (`string`, nullable, format `date-time`)
- `refreshDays` (`integer`, nullable, one of `1`, `7`, `30`): Links only: the page is read again every this many days, and changes reach the AI on their own. Null when it is read only when you ask.
- `nextRefreshAt` (`string`, nullable, format `date-time`): When the page is next read again. Null when it is not scheduled.
- `connectorId` (`string`, nullable): The connector that keeps this item in step with its source, or null for an item added by hand.
- `threadId` (`string`, nullable): The conversation the note was saved from, or null.
- `uses` (`integer`): How many times it came up in a reply suggestion, a draft, the assistant or a search.
- `lastUsedAt` (`string`, nullable, format `date-time`)
- `flags` (`integer`): How many open duplicate or conflict flags name it. Lists and `GET /knowledge/{id}` count them, and the answer to a change says 0.
- `body` (`string`, nullable): The text of a note. Null for files and links.
- `preview` (`string`, nullable): The text the AI reads, from the start. Null while a file or page has not been read yet.
- `previewTruncated` (`boolean`): True when the text goes on past the preview.

#### `KnowledgeItemList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`KnowledgeItem[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

#### `KnowledgeLevel`

`object`

- `object` (`string`, one of `"knowledge_level"`)
- `scope` (`string`): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, one of `"workspace"`, `"domain"`, `"address"`)
- `writable` (`boolean`): Whether the caller may add and change items here.
- `items` (`integer`)

#### `KnowledgeLevelList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`KnowledgeLevel[]`)

#### `KnowledgeSearchHit`

`object`

- `sourceId` (`string`): The item the passage comes from.
- `title` (`string`)
- `kind` (`string`, one of `"note"`, `"file"`, `"link"`)
- `scope` (`string`)
- `level` (`string`, one of `"workspace"`, `"domain"`, `"address"`)
- `url` (`string`, nullable)
- `heading` (`string`): The headings the passage sits under, joined with ` > `.
- `text` (`string`)
- `score` (`number`): Higher is a better match. Only the order means anything.

#### `KnowledgeSearchResult`

`object`

- `object` (`string`, one of `"knowledge_search"`)
- `query` (`string`)
- `hits` (`KnowledgeSearchHit[]`)
- `reranked` (`boolean`): True when the AI put the passages in order, as `rerank` asks.

#### `KnowledgeStats`

`object`

- `object` (`string`, one of `"knowledge_stats"`)
- `days` (`integer`)
- `uses` (`integer`): Times the AI found something in the knowledge base.
- `empty` (`integer`): Times it looked and found nothing.
- `coverage` (`number`): uses divided by uses and empty together, from 0 to 1. 0 when it never looked.
- `bySurface` (`Record<string, integer>`): `uses` by where they happened: `compose`, `reply`, `chat`, `tool`, `search`.
- `series` (`object[]`): One entry per day, oldest first, days with nothing included.
  - `day` (`string`, format `date`)
  - `uses` (`integer`)
  - `empty` (`integer`)
- `topItems` (`object[]`): The items used most, ever.
  - `id` (`string`)
  - `title` (`string`)
  - `kind` (`string`, one of `"note"`, `"file"`, `"link"`)
  - `scope` (`string`)
  - `uses` (`integer`)
  - `lastUsedAt` (`string`, nullable, format `date-time`)
- `unusedItems` (`integer`): Ready items the AI has never used.
- `pendingSuggestions` (`integer`)
- `openQuestions` (`integer`)
- `openFlags` (`integer`)

#### `KnowledgeSuggestion`

`object`

- `object` (`string`, required, one of `"knowledge_suggestion"`)
- `id` (`string`, required)
- `kind` (`string`, required, one of `"learned"`, `"question"`): `learned` is a fact the AI found in a reply sent from the workspace. `question` is something a sender asked that nothing in the knowledge base answers.
- `status` (`string`, required, one of `"pending"`, `"accepted"`, `"dismissed"`)
- `scope` (`string`, required): A `scope` is empty for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI working for an address reads that address, then its domain, then the whole workspace, the most specific first.
- `level` (`string`, required, one of `"workspace"`, `"domain"`, `"address"`)
- `title` (`string`, required): The suggested title, or the question.
- `body` (`string`, required, nullable): The suggested note. Null for a question, which needs its answer when it is accepted.
- `occurrences` (`integer`, required): How many times the same fact or question came up.
- `threadId` (`string`, required, nullable): The conversation it came from most recently.
- `sourceId` (`string`, required, nullable): The note made from it, once it is accepted.
- `createdAt` (`string`, required, format `date-time`)
- `updatedAt` (`string`, required, format `date-time`)
- `decidedAt` (`string`, required, nullable, format `date-time`)

#### `KnowledgeSuggestionAccepted`

`object`

- `object` (`string`, required, one of `"knowledge_suggestion_accepted"`)
- `suggestion` (`KnowledgeSuggestion`, required)
- `item` (`KnowledgeItem`, required)

#### `KnowledgeSuggestionList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`KnowledgeSuggestion[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

#### `KnowledgeUsage`

`object`

- `object` (`string`, one of `"knowledge_usage"`)
- `plan` (`string`, one of `"free"`, `"starter"`, `"business"`, `"enterprise"`)
- `sources` (`integer`): Items held.
- `chars` (`integer`): Characters of text held.
- `limits` (`object`)
  - `sources` (`integer`)
  - `chars` (`integer`)
