---
title: "openemail.knowledge"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://openemail.uk/docs/sdk/reference/knowledge"
area: "TypeScript"
category: "Reference"
---

# openemail.knowledge

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

The notes, files and web pages the AI uses when it writes replies, drafts email and answers in the assistant, each kept for the whole workspace, one domain or one address: list and search them, add a note, a link or a file, change, read again and delete them, and see the levels and how much the plan allows. Review the notes the AI suggests and the questions nothing answers, settle duplicate and conflict flags, keep a site, sitemap, feed or Zendesk help center in step with connectors, draft a note from a conversation, and read how often the AI used it.

### `knowledge.list()`

List one page of the knowledge base

```ts
list(options?: KnowledgeListOptions): Promise<Page<KnowledgeItemResource>>
```

Resolves one page of the knowledge base, newest first: the notes, files and web pages the AI uses when it writes replies, drafts email and answers in the assistant. Each item says where it sits, whether the AI can use it yet and how much text was read from it. `listAll` collects every page and `iterate` walks them lazily.

Every item sits at one level, its `scope`: an empty string for the whole workspace, `@` and a domain for everything on that domain (`@acme.com`), or one address (`sales@acme.com`). The AI writing for an address reads that address, then its domain, then the whole workspace, the most specific first. `level` names the kind of level, `workspace`, `domain` or `address`.

`status` is `queued` or `processing` while the text is read and indexed, `ready` once the AI can use it, and `failed` with a `failure` when it could not be read. A key or an app limited to particular addresses sees the whole-workspace items and the items at its addresses and at their domains.

Each item also says how the AI uses it: `uses` counts the times it came up in a reply suggestion, a draft, the assistant or a search, with `lastUsedAt` the latest, and `flags` counts the open duplicate and conflict flags that name it. A link read again on a schedule has `refreshDays` and `nextRefreshAt`, a page kept by a connector names it in `connectorId`, and a note saved from a conversation names it in `threadId`.

Scopes: `knowledge:read`.

**Parameters**

- `options.scope` (`string`): Keeps the items at exactly this level: `@` and a domain such as `@acme.com`, or one address. An empty string is not sent, so ask for the whole-workspace items with `level: 'workspace'`.
- `options.level` (`KnowledgeLevel`): Keeps one kind of level: `workspace`, `domain` or `address`.
- `options.kind` (`KnowledgeKind`): Keeps one kind of item: `note`, `file` or `link`.
- `options.status` (`KnowledgeStatus`): Keeps one status: `queued`, `processing`, `ready` or `failed`.
- `options.pinned` (`boolean`): `true` keeps the pinned notes and `false` everything else.
- `options.q` (`string`): Words in the title, the file name or the link, matched without regard to case or accents.
- `options.limit` (`number`): Page size, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): The `nextCursor` of the previous page. Leave it out for the first page.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`Page<KnowledgeItemResource>` with `items`, `hasMore` and `nextCursor`. Each item has `id`, `kind`, `scope`, `level`, `title`, `url`, `fileName`, `mimeType`, `sizeBytes`, `pinned`, `status`, `failure`, `chunks`, `chars`, `origin`, `createdBy`, `createdAt`, `updatedAt`, `indexedAt`, `refreshDays`, `nextRefreshAt`, `connectorId`, `threadId`, `uses`, `lastUsedAt` and `flags`.

**Example**

```ts
const page = await openemail.knowledge.list({ level: 'domain', kind: 'file' })

for (const item of page.items) console.log(item.scope, item.title, item.status)
```

**Notes**

- Needs `knowledge:read`, which `knowledge:write` includes.
- The cursor is opaque. One this list did not hand out is a 400 `invalid_cursor`. A `scope` that is neither a domain nor an address is a 422 `invalid_knowledge_scope`, and a level the key cannot see lists nothing.

Also available in: API [`GET /knowledge`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge); Python [`knowledge.list()`](https://openemail.uk/docs/python/reference/knowledge#list); Ruby [`knowledge.list`](https://openemail.uk/docs/ruby/reference/knowledge#list); PHP [`knowledge->list`](https://openemail.uk/docs/php/reference/knowledge#list); CLI [`openemail knowledge list`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list).

### `knowledge.listAll()`

Collect every knowledge item into one array

```ts
listAll(options?: KnowledgeListOptions): Promise<Array<KnowledgeItemResource>>
```

Walks every page of `list` and resolves with every item, newest first. One request per page, with the same filters on each.

Scopes: `knowledge:read`.

**Parameters**

- `options.scope` (`string`): Keeps the items at exactly this level: `@` and a domain such as `@acme.com`, or one address. An empty string is not sent, so ask for the whole-workspace items with `level: 'workspace'`.
- `options.level` (`KnowledgeLevel`): Keeps one kind of level: `workspace`, `domain` or `address`.
- `options.kind` (`KnowledgeKind`): Keeps one kind of item: `note`, `file` or `link`.
- `options.status` (`KnowledgeStatus`): Keeps one status: `queued`, `processing`, `ready` or `failed`.
- `options.pinned` (`boolean`): `true` keeps the pinned notes and `false` everything else.
- `options.q` (`string`): Words in the title, the file name or the link, matched without regard to case or accents.
- `options.limit` (`number`): Page size for each request, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): Starts the walk after this cursor instead of the first page.
- `options.signal` (`AbortSignal`): Cancels the request in flight and the walk with it.
- `options.apiKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

`Array<KnowledgeItemResource>` holding every item.

**Example**

```ts
const failed = await openemail.knowledge.listAll({ status: 'failed' })

for (const item of failed) console.log(item.title, item.failure)
```

**Notes**

- If any page fails the promise rejects and the items already fetched are discarded.

Also available in: API [`GET /knowledge`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge); Python [`knowledge.list_all()`](https://openemail.uk/docs/python/reference/knowledge#listAll); Ruby [`knowledge.list_all`](https://openemail.uk/docs/ruby/reference/knowledge#listAll); PHP [`knowledge->listAll`](https://openemail.uk/docs/php/reference/knowledge#listAll).

### `knowledge.iterate()`

Stream the knowledge items one at a time

```ts
iterate(options?: KnowledgeListOptions): AsyncGenerator<KnowledgeItemResource, void, undefined>
```

Returns an async generator that yields one item at a time, newest first, and requests the next page only once the current one is drained. Nothing is fetched until you consume it, and breaking out of the loop stops the requests.

Scopes: `knowledge:read`.

**Parameters**

- `options.scope` (`string`): Keeps the items at exactly this level: `@` and a domain such as `@acme.com`, or one address. An empty string is not sent, so ask for the whole-workspace items with `level: 'workspace'`.
- `options.level` (`KnowledgeLevel`): Keeps one kind of level: `workspace`, `domain` or `address`.
- `options.kind` (`KnowledgeKind`): Keeps one kind of item: `note`, `file` or `link`.
- `options.status` (`KnowledgeStatus`): Keeps one status: `queued`, `processing`, `ready` or `failed`.
- `options.pinned` (`boolean`): `true` keeps the pinned notes and `false` everything else.
- `options.q` (`string`): Words in the title, the file name or the link, matched without regard to case or accents.
- `options.limit` (`number`): Page size for each request, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): Starts the walk after this cursor instead of the first page.
- `options.signal` (`AbortSignal`): Cancels the request in flight and the walk with it.
- `options.apiKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

`AsyncGenerator<KnowledgeItemResource, void, undefined>` yielding one item per step.

**Example**

```ts
for await (const item of openemail.knowledge.iterate({ pinned: true })) {
    console.log(item.scope || 'whole workspace', item.title)
}
```

**Notes**

- The generator is lazy, so an abandoned loop costs only the pages you consumed.

Also available in: API [`GET /knowledge`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge); Python [`knowledge.iterate()`](https://openemail.uk/docs/python/reference/knowledge#iterate); Ruby [`knowledge.iterate`](https://openemail.uk/docs/ruby/reference/knowledge#iterate); PHP [`knowledge->iterate`](https://openemail.uk/docs/php/reference/knowledge#iterate).

### `knowledge.levels()`

List the levels knowledge can sit at

```ts
levels(options?: RequestScope): Promise<Array<KnowledgeLevelResource>>
```

Resolves every level the caller can see: the whole workspace first, then each domain, then each address, with how many items each holds and whether the caller may add and change items there. Pass its `scope` when you add an item.

A key or an app limited to particular addresses sees the whole workspace, its addresses and their domains. `writable` is true at the whole workspace only for a caller that reaches every address, at a domain for one that holds the whole domain, and at an address for one that holds that address.

Scopes: `knowledge:read`.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`Array<KnowledgeLevelResource>`, each with `scope`, `level`, `writable` and `items`.

**Example**

```ts
const levels = await openemail.knowledge.levels()

const writable = levels.filter((level) => level.writable)

console.log(writable.map((level) => level.scope || 'whole workspace'))
```

**Notes**

- Needs `knowledge:read`. A removed address is not a level.

Also available in: API [`GET /knowledge/levels`](https://openemail.uk/docs/api/reference/knowledge#get-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).

### `knowledge.usage()`

Read how much of the plan the knowledge base uses

```ts
usage(options?: RequestScope): Promise<KnowledgeUsageResource>
```

Resolves how many items and how many characters of text the workspace keeps in its knowledge base, beside what its plan allows in `limits`: 50 items and 1,000,000 characters on Free, 500 and 10,000,000 on Starter, 2,000 and 50,000,000 on Business, and 10,000 and 200,000,000 on Enterprise.

An item counts as soon as it is added, and its characters once its text has been read. The numbers are for the whole workspace, whatever the key may reach.

Scopes: `knowledge:read`.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeUsageResource` with `plan`, `sources`, `chars` and `limits`, which holds `sources` and `chars`.

**Example**

```ts
const usage = await openemail.knowledge.usage()

console.log(`${usage.sources} of ${usage.limits.sources} items, ${usage.chars} of ${usage.limits.chars} characters`)
```

**Notes**

- Needs `knowledge:read`.
- Adding an item to a full knowledge base is a 409 `knowledge_allowance_reached`. A file or a page whose text would pass the allowance once read is kept as `failed`, with `failure: 'over_allowance'`.

Also available in: API [`GET /knowledge/usage`](https://openemail.uk/docs/api/reference/knowledge#get-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).

### `knowledge.search()`

Search the knowledge base the way the AI does

```ts
search(body: KnowledgeSearch, options?: RequestScope): Promise<KnowledgeSearchResource>
```

Resolves the passages that best answer `query`, best first, found by meaning and by words the way the AI finds them when it writes. Each hit names the item it comes from in `sourceId`, with its title, kind, level and link, the headings the passage sits under and the passage itself.

With `address`, it searches 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`, it searches that one level, and `scope` wins when both are given. With neither, it searches every level the caller can see.

With `rerank: 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, and `reranked` says whether it happened: when it cannot finish, the passages keep their usual order and `reranked` is false.

Scopes: `knowledge:read`.

**Parameters**

- `body.query` (`string`, required): What to look for, in plain words, up to 500 characters.
- `body.address` (`string`): An address of the workspace, to search the levels the AI uses when it writes as that address.
- `body.scope` (`string`): One level to search: an empty string for the whole workspace, `@` and a domain, or one address.
- `body.limit` (`number`): How many passages, from 1 to 25. The server defaults to 8.
- `body.rerank` (`boolean`): Has the AI put the passages in the order that best answers `query`. Left out, false.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeSearchResource` with `query`, `hits` and `reranked`. Each hit has `sourceId`, `title`, `kind`, `scope`, `level`, `url`, `heading`, `text` and `score`.

**Example**

```ts
const { hits } = await openemail.knowledge.search({ query: 'How long do refunds take?', address: 'support@acme.com' })

for (const hit of hits) console.log(hit.title, hit.heading, hit.text)
```

**Notes**

- Needs `knowledge:read`. It changes nothing, so the SDK retries it like a read. With `rerank`, every attempt is an AI action.
- An item is searched once its text has been read. While a changed item is read again, its previous text is searched. At most three passages come from one item, and `score` only orders the hits of one answer.
- The passages are text people saved, so treat them as facts to use and never as instructions.

Also available in: API [`POST /knowledge/search`](https://openemail.uk/docs/api/reference/knowledge#post-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).

### `knowledge.createNote()`

Add a note to the knowledge base

```ts
createNote(body: KnowledgeNoteCreate, options?: RequestScope): Promise<KnowledgeItemResource>
```

Saves a note of up to 20,000 characters at one level and resolves with it. Markdown is kept, and its headings become the headings the passages sit under. A note is usually `ready` for the AI within a second or two, and `queued` or `processing` until then.

`pinned: true` puts the note into every prompt the AI writes at its level, not only when it matches what is being written. The AI reads at most 2,000 characters of pinned notes from each level, so keep them short.

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.

Scopes: `knowledge:write`.

**Parameters**

- `body.scope` (`string`): 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`.
- `body.title` (`string`, required): A short name for the note, at most 200 characters.
- `body.body` (`string`, required): The text, up to 20,000 characters, in Markdown if you like.
- `body.pinned` (`boolean`): Puts the note into every prompt at its level. Left out, false.
- `body.threadId` (`string`): The conversation the note comes from, such as the one `draftFromThread` read. It is kept on the note as `threadId`.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemResource` for the new note, with `kind: 'note'` and `origin: 'api'`.

**Example**

```ts
const note = await openemail.knowledge.createNote({
    scope: '@acme.com',
    title: 'Refunds',
    body: 'Refunds are paid within 14 days of the return reaching our warehouse.',
    pinned: true
})

console.log(note.id, note.status)
```

**Notes**

- Needs `knowledge:write`.
- A level that is not the workspace, one of its domains or one of its addresses is a 422 `invalid_knowledge_scope`, and a level outside what the key reaches is a 403 `knowledge_scope_not_reached`. A full knowledge base is a 409 `knowledge_allowance_reached`.
- The SDK does not retry it, because a second attempt after a lost response could save the note twice. Look for it with `list` before trying again.

Also available in: API [`POST /knowledge/notes`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-notes); 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).

### `knowledge.addLink()`

Add a web page to the knowledge base

```ts
addLink(body: KnowledgeLinkCreate, options?: RequestScope): Promise<KnowledgeItemResource>
```

Adds a public web page at one level and resolves with it, `queued`. The page is fetched and read in the background, and the AI uses it once its `status` is `ready`. Without a `title`, the item is named after the link until the page is read, and then after the page's own title.

`url` is a public `http` or `https` address of at most 2,048 characters, and it is kept as `https`. An address on a private or local host, or one with a user name, a password or a port, is refused. A level holds a page once, and `refresh` fetches it again after it changes. With `refreshDays`, the page is also read again every 1, 7 or 30 days on its own, `nextRefreshAt` says when, and a changed page reaches the AI without a call.

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.

Scopes: `knowledge:write`.

**Parameters**

- `body.scope` (`string`): 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`.
- `body.url` (`string`, required): The page, a public `http` or `https` address of at most 2,048 characters.
- `body.title` (`string`): A name for the item, at most 200 characters. Left out, the page's own title once it has been read.
- `body.refreshDays` (`KnowledgeRefreshDays | null`): Reads the page again every 1, 7 or 30 days. Left out or `null`, it is read again only when you call `refresh`.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemResource` for the new link, with `kind: 'link'` and `status: 'queued'`.

**Example**

```ts
const page = await openemail.knowledge.addLink({ url: 'https://acme.com/shipping', scope: '@acme.com' })

console.log(page.id, page.status)
```

**Notes**

- Needs `knowledge:write`.
- A link that is not a public web address is a 422 `invalid_knowledge_url`, and the same link at the same level is a 409 `knowledge_link_exists`. A `refreshDays` other than 1, 7, 30 or null is a 422 `invalid_knowledge_refresh`. A level that is not the workspace, one of its domains or one of its addresses is a 422 `invalid_knowledge_scope`, and a level outside what the key reaches is a 403 `knowledge_scope_not_reached`.
- A page that cannot be fetched ends `failed` with `failure: 'fetch_failed'`, and one that resolves to a blocked host with `failure: 'blocked_url'`. At most 5 MB of a page is read.
- The SDK does not retry it. A second attempt after a lost response answers 409 `knowledge_link_exists`, which means the first one worked.

Also available in: API [`POST /knowledge/links`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-links); 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).

### `knowledge.uploadFile()`

Upload a file to the knowledge base

```ts
uploadFile(data: RawBody, options: KnowledgeFileUploadOptions): Promise<KnowledgeItemResource>
```

Stores a document or an image at one level and resolves with it, `queued`. Its text is read in the background, and the AI uses it once its `status` is `ready`. PDFs, Word documents, spreadsheets (Excel, OpenDocument, Numbers and CSV), OpenDocument text, HTML, XML, Markdown, plain text, JSON and images (JPEG, PNG, WebP and SVG) can be read.

`data` is a `Blob`, an `ArrayBuffer` or a `Uint8Array`, sent as the request body. The name travels as the `filename` query parameter, and the type is `options.contentType`, a `Blob`'s own type when that is left out, or the extension of the name when the type is generic. A document can be up to 20 MB and an image up to 10 MB.

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.

Scopes: `knowledge:write`.

**Parameters**

- `data` (`RawBody`, required): The file: a `Blob`, `ArrayBuffer` or `Uint8Array`, not empty, at most 20 MB for a document and 10 MB for an image.
- `options.filename` (`string`, required): The file name, such as `price-list.pdf`. Its extension tells the kind of file when the type is generic. A missing or blank name throws before anything is sent.
- `options.contentType` (`string`): The MIME type, such as `application/pdf`. Left out, a `Blob`'s own type is used, else the extension of `filename`.
- `options.scope` (`string`): 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`.
- `options.title` (`string`): A name for the item, at most 200 characters. Left out, the file name without its extension.
- `options.timeoutMs` (`number`): How long the upload may take, in milliseconds. Left out, it is 10 minutes, or the client `timeoutMs` when that is longer. `0` waits as long as it takes.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemResource` for the new file, with `kind: 'file'`, its `fileName`, `mimeType` and `sizeBytes`, and `status: 'queued'`.

**Example**

```ts
import { openAsBlob } from 'node:fs'

const file = await openemail.knowledge.uploadFile(await openAsBlob('price-list.pdf'), {
    filename: 'price-list.pdf',
    contentType: 'application/pdf',
    scope: 'sales@acme.com'
})

console.log(file.id, file.title, file.status)
```

**Notes**

- Needs `knowledge:write`.
- A kind of file that cannot be read is a 422 `knowledge_file_unsupported`, an empty file a 422 `knowledge_file_empty`, and a file over the limit a 413 `knowledge_file_too_large`. A level that is not the workspace, one of its domains or one of its addresses is a 422 `invalid_knowledge_scope`, and a level outside what the key reaches is a 403 `knowledge_scope_not_reached`. A full knowledge base is a 409 `knowledge_allowance_reached`.
- A file with no text in it ends `failed` with `failure: 'empty'`, and one that could not be turned into text with `failure: 'conversion_failed'`.
- The SDK does not retry an upload, because a second attempt after a lost response could store the file twice. Look for it with `list` before trying again.

Also available in: API [`POST /knowledge/files`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-files); 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).

### `knowledge.get()`

Read one knowledge item and its text

```ts
get(id: string, options?: RequestScope): Promise<KnowledgeItemDetailResource>
```

Resolves one item with its text: the `body` of a note, or in `preview` the first 20,000 characters read from a file or a page, with `previewTruncated` true when the text goes on past it. `preview` is null while a file or a page has not been read yet, and `body` is null for anything but a note.

Scopes: `knowledge:read`.

**Parameters**

- `id` (`string`, required): The id of the item, `kb_` and 24 hex characters, as `list` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemDetailResource`, the fields `list` returns plus `body`, `preview` and `previewTruncated`.

**Example**

```ts
const item = await openemail.knowledge.get('kb_8c1f4a2b9d7e3f60a5c7b21d')

console.log(item.title, item.body ?? item.preview)
```

**Notes**

- Needs `knowledge:read`. An unknown id, and an item at a level the key cannot see, answer 404 `knowledge_not_found`.

Also available in: API [`GET /knowledge/{id}`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-id); 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).

### `knowledge.update()`

Change a knowledge item

```ts
update(id: string, patch: KnowledgePatch, options?: RequestScope): Promise<KnowledgeItemResource>
```

Changes the title of an item, the text of a note, the page of a link, how often a link is read again, whether a note is pinned, or its level, and resolves with the item as it is now. Give at least one field. A changed title, text or link is read and indexed again, so the item goes back to `queued`, and its previous text stays in use until the new one is ready. Moving an item to another level needs no new reading.

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.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the item, `kb_` and 24 hex characters, as `list` returns it.
- `patch.title` (`string`): A new name, at most 200 characters.
- `patch.body` (`string`): The new text of a note, up to 20,000 characters.
- `patch.scope` (`string`): The level to move it to: an empty string for the whole workspace, `@` and a domain, or one address.
- `patch.pinned` (`boolean`): Whether a note goes into every prompt at its level.
- `patch.url` (`string`): The new page of a link, a public `http` or `https` address.
- `patch.refreshDays` (`KnowledgeRefreshDays | null`): Reads a link again every 1, 7 or 30 days, counted from now. `null` stops that.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemResource` as it is now.

**Example**

```ts
const item = await openemail.knowledge.update('kb_8c1f4a2b9d7e3f60a5c7b21d', {
    body: 'Refunds are paid within 10 days of the return reaching our warehouse.',
    pinned: true
})

console.log(item.status, item.updatedAt)
```

**Notes**

- Needs `knowledge:write`. An empty patch is a 422 `invalid_parameter`.
- `body` or `pinned` on anything but a note is a 422 `knowledge_not_a_note`, and `url` or `refreshDays` on anything but a link a 422 `knowledge_not_a_link`. A `refreshDays` other than 1, 7, 30 or null is a 422 `invalid_knowledge_refresh`. Moving a link to a level that already holds it is a 409 `knowledge_link_exists`, and a note that grows past the allowance a 409 `knowledge_allowance_reached`.
- Retried automatically on network failure and retryable statuses, since the same patch applied twice leaves the same item.

Also available in: API [`PATCH /knowledge/{id}`](https://openemail.uk/docs/api/reference/knowledge#patch-knowledge-id); 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).

### `knowledge.delete()`

Delete a knowledge item for good

```ts
delete(id: string, options?: RequestScope): Promise<DeletedKnowledgeItemResource>
```

Removes an item with its file and every passage read from it, and the AI stops using it at once. There is no undo.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the item, `kb_` and 24 hex characters, as `list` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`DeletedKnowledgeItemResource`, `{ object: 'knowledge_item', id, deleted: true }`.

**Example**

```ts
const removed = await openemail.knowledge.delete('kb_8c1f4a2b9d7e3f60a5c7b21d')

console.log(removed.deleted)
```

**Notes**

- Needs `knowledge:write`, and reach over the level of the item. An unknown id is a 404 `knowledge_not_found`.
- The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.

Also available in: API [`DELETE /knowledge/{id}`](https://openemail.uk/docs/api/reference/knowledge#delete-knowledge-id); 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).

### `knowledge.refresh()`

Read a knowledge item again

```ts
refresh(id: string, options?: RequestScope): Promise<KnowledgeItemResource>
```

Fetches a link again, reads a file again or indexes a note again, clears any `failure` and resolves with the item, back at `queued`. Use it after a page changed or when an item failed. The previous text stays in use until the new one is ready.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the item, `kb_` and 24 hex characters, as `list` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeItemResource`, queued to be read again.

**Example**

```ts
const failed = await openemail.knowledge.listAll({ status: 'failed' })

for (const item of failed) await openemail.knowledge.refresh(item.id)
```

**Notes**

- Needs `knowledge:write`, and reach over the level of the item.
- Reading an item again twice leaves it the same way, so the SDK retries it on network failure and retryable statuses.

Also available in: API [`POST /knowledge/{id}/refresh`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-id-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).

### `knowledge.stats()`

Read how the AI used the knowledge base

```ts
stats(options?: KnowledgeStatsOptions): Promise<KnowledgeStatsResource>
```

Resolves how the AI used the knowledge base over the last `days` days, today included, 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. `coverage` is `uses` divided by the two together, from 0 to 1, and 0 when it never looked. `bySurface` splits `uses` by where they happened, under the keys `compose`, `reply`, `chat`, `tool` and `search`, and `series` has one entry per day, oldest first, days with nothing included.

`topItems` lists the items used most, ever, and `unusedItems` counts the ready items the AI has never used. `pendingSuggestions` counts the learned notes waiting for review, `openQuestions` the questions senders asked that nothing answers yet, and `openFlags` the open duplicate and conflict flags. `uses`, `empty`, `bySurface` and `series` cover the whole workspace, while the items, suggestions, questions and flags count only what the caller can see.

Scopes: `knowledge:read`.

**Parameters**

- `options.days` (`number`): How many days back to count, today included, from 1 to 90. The server defaults to 30.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeStatsResource` with `days`, `uses`, `empty`, `coverage`, `bySurface`, `series`, `topItems`, `unusedItems`, `pendingSuggestions`, `openQuestions` and `openFlags`. Each day in `series` is `{ day, uses, empty }`, and each of `topItems` is `{ id, title, kind, scope, uses, lastUsedAt }`.

**Example**

```ts
const stats = await openemail.knowledge.stats({ days: 7 })

console.log(`${Math.round(stats.coverage * 100)}% of lookups found something`)

for (const item of stats.topItems) console.log(item.uses, item.title)
```

**Notes**

- Needs `knowledge:read`. It changes nothing, so the SDK retries it like any other read.
- A `days` outside 1 to 90 is a 422 `invalid_parameter`.

Also available in: API [`GET /knowledge/stats`](https://openemail.uk/docs/api/reference/knowledge#get-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).

### `knowledge.listSuggestions()`

List one page of knowledge suggestions and questions

```ts
listSuggestions(options?: KnowledgeSuggestionListOptions): Promise<Page<KnowledgeSuggestionResource>>
```

Resolves one page of what the AI suggests adding to the knowledge base, the most recent first, pending ones unless you ask for another `status`. `listAllSuggestions` collects every page and `iterateSuggestions` walks them lazily.

A `learned` suggestion is a note the AI drew from a reply sent from the workspace: it 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` is something a sender asked about the business that neither the conversation nor the knowledge base answers: when the AI suggests replies to an incoming message, it notes up to 3 such questions, at the level of the domain the message arrived at, chosen the same way. Accept a question with its answer and it becomes a note.

The same fact or question again counts up `occurrences` instead of adding a second suggestion, and one that was dismissed is not suggested again. Both kinds stop while the workspace setting `knowledgeLearning` is off, which `settings.update` changes.

Scopes: `knowledge:read`.

**Parameters**

- `options.kind` (`KnowledgeSuggestionKind`): Keeps one kind: `learned` for notes drawn from sent replies, or `question` for questions nothing answers.
- `options.status` (`KnowledgeSuggestionStatus`): Keeps one status: `pending`, `accepted` or `dismissed`. Left out, `pending`.
- `options.limit` (`number`): Page size, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): The `nextCursor` of the previous page. Leave it out for the first page.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`Page<KnowledgeSuggestionResource>` with `items`, `hasMore` and `nextCursor`. Each suggestion has `id`, `kind`, `status`, `scope`, `level`, `title`, `body`, `occurrences`, `threadId`, `sourceId`, `createdAt`, `updatedAt` and `decidedAt`.

**Example**

```ts
const page = await openemail.knowledge.listSuggestions({ kind: 'question' })

for (const question of page.items) console.log(question.occurrences, question.title)
```

**Notes**

- Needs `knowledge:read`, which `knowledge:write` includes.
- A `learned` suggestion holds the suggested note in `title` and `body`. A `question` holds the question in `title`, and its `body` is null until it is answered. `threadId` names the conversation it came from most recently, and `sourceId` the note made from it once it is accepted.
- A key or an app limited to particular addresses sees the suggestions at the whole workspace, at its addresses and at their domains. The cursor is opaque, and one this list did not hand out is a 400 `invalid_cursor`.

Also available in: API [`GET /knowledge/suggestions`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-suggestions); Python [`knowledge.list_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#listSuggestions); Ruby [`knowledge.list_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#listSuggestions); PHP [`knowledge->listSuggestions`](https://openemail.uk/docs/php/reference/knowledge#listSuggestions); CLI [`openemail knowledge list-suggestions`](https://openemail.uk/docs/cli/reference/knowledge#knowledge-list-suggestions).

### `knowledge.listAllSuggestions()`

Collect every knowledge suggestion into one array

```ts
listAllSuggestions(options?: KnowledgeSuggestionListOptions): Promise<Array<KnowledgeSuggestionResource>>
```

Walks every page of `listSuggestions` and resolves with every suggestion or question that matches, the most recent first. One request per page, with the same filters on each.

Scopes: `knowledge:read`.

**Parameters**

- `options.kind` (`KnowledgeSuggestionKind`): Keeps one kind: `learned` for notes drawn from sent replies, or `question` for questions nothing answers.
- `options.status` (`KnowledgeSuggestionStatus`): Keeps one status: `pending`, `accepted` or `dismissed`. Left out, `pending`.
- `options.limit` (`number`): Page size for each request, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): Starts the walk after this cursor instead of the first page.
- `options.signal` (`AbortSignal`): Cancels the request in flight and the walk with it.
- `options.apiKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

`Array<KnowledgeSuggestionResource>` holding every suggestion and question that matches.

**Example**

```ts
const questions = await openemail.knowledge.listAllSuggestions({ kind: 'question' })

console.log(`${questions.length} questions wait for an answer`)
```

**Notes**

- If any page fails the promise rejects and the suggestions already fetched are discarded.

Also available in: API [`GET /knowledge/suggestions`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-suggestions); Python [`knowledge.list_all_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#listAllSuggestions); Ruby [`knowledge.list_all_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#listAllSuggestions); PHP [`knowledge->listAllSuggestions`](https://openemail.uk/docs/php/reference/knowledge#listAllSuggestions).

### `knowledge.iterateSuggestions()`

Stream the knowledge suggestions one at a time

```ts
iterateSuggestions(options?: KnowledgeSuggestionListOptions): AsyncGenerator<KnowledgeSuggestionResource, void, undefined>
```

Returns an async generator that yields one suggestion or question at a time, the most recent first, and requests the next page only once the current one is drained. Nothing is fetched until you consume it, and breaking out of the loop stops the requests.

Scopes: `knowledge:read`.

**Parameters**

- `options.kind` (`KnowledgeSuggestionKind`): Keeps one kind: `learned` for notes drawn from sent replies, or `question` for questions nothing answers.
- `options.status` (`KnowledgeSuggestionStatus`): Keeps one status: `pending`, `accepted` or `dismissed`. Left out, `pending`.
- `options.limit` (`number`): Page size for each request, from 1 to 100. The server defaults to 50.
- `options.cursor` (`string`): Starts the walk after this cursor instead of the first page.
- `options.signal` (`AbortSignal`): Cancels the request in flight and the walk with it.
- `options.apiKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

`AsyncGenerator<KnowledgeSuggestionResource, void, undefined>` yielding one suggestion or question per step.

**Example**

```ts
for await (const suggestion of openemail.knowledge.iterateSuggestions({ kind: 'learned' })) {
    console.log(suggestion.scope || 'whole workspace', suggestion.title)
}
```

**Notes**

- The generator is lazy, so an abandoned loop costs only the pages you consumed.

Also available in: API [`GET /knowledge/suggestions`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-suggestions); Python [`knowledge.iterate_suggestions()`](https://openemail.uk/docs/python/reference/knowledge#iterateSuggestions); Ruby [`knowledge.iterate_suggestions`](https://openemail.uk/docs/ruby/reference/knowledge#iterateSuggestions); PHP [`knowledge->iterateSuggestions`](https://openemail.uk/docs/php/reference/knowledge#iterateSuggestions).

### `knowledge.acceptSuggestion()`

Save a knowledge suggestion as a note

```ts
acceptSuggestion(id: string, body?: KnowledgeSuggestionAccept, options?: RequestScope): Promise<KnowledgeSuggestionAcceptedResource>
```

Saves a pending suggestion or question as a note, marks it `accepted` and resolves with both: the suggestion, its `sourceId` naming the new note, and the note itself in `item`. Any field you send takes the place of the suggested one, so you can tidy the title, rewrite the text, move it to another level or pin it on the way in. The note keeps the conversation the suggestion came from in `threadId`.

A question needs its answer in `body`, and its title stays the question unless you send one. Answering a question this way is how it becomes a note the AI uses from then on.

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.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the suggestion or question, `kp_` and 24 hex characters, as `listSuggestions` returns it.
- `body.title` (`string`): A title for the note, at most 200 characters. Left out, the suggested title or the question.
- `body.body` (`string`): The text of the note, up to 20,000 characters. Left out, the suggested note. A question needs it: the answer.
- `body.scope` (`string`): The level for the note: an empty string for the whole workspace, `@` and a domain, or one address. Left out, the suggested level.
- `body.pinned` (`boolean`): Puts the note into every prompt at its level. Left out, false.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeSuggestionAcceptedResource`, `{ object: 'knowledge_suggestion_accepted', suggestion, item }`, with the suggestion `accepted` and the new note as a `KnowledgeItemResource`.

**Example**

```ts
const { item } = await openemail.knowledge.acceptSuggestion('kp_3f9a1c7e5b2d8046a1c3e5f7', {
    body: 'Orders over 50 euros ship free within the EU.'
})

console.log(item.id, item.title, item.status)
```

**Notes**

- Needs `knowledge:write`, and reach over the level the note lands at.
- An unknown id, and a suggestion at a level the key cannot see, answer 404 `knowledge_suggestion_not_found`. One that was already accepted or dismissed is a 409 `knowledge_suggestion_decided`, and a question accepted without `body` a 422 `knowledge_answer_required`. A full knowledge base is a 409 `knowledge_allowance_reached`, and the suggestion stays pending.
- The SDK does not retry it. A 409 `knowledge_suggestion_decided` on your own second attempt after a lost response means the first one worked.

Also available in: API [`POST /knowledge/suggestions/{id}/accept`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-suggestions-id-accept); 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).

### `knowledge.dismissSuggestion()`

Dismiss a knowledge suggestion or question

```ts
dismissSuggestion(id: string, options?: RequestScope): Promise<KnowledgeSuggestionResource>
```

Marks a pending suggestion or question `dismissed` and resolves with it. It leaves the pending list, the same fact or question is not suggested again, and nothing is added to the knowledge base.

Dismissing needs the reach to add a note at the level of the suggestion: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the suggestion or question, `kp_` and 24 hex characters, as `listSuggestions` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeSuggestionResource` with `status: 'dismissed'` and `decidedAt` set.

**Example**

```ts
const dismissed = await openemail.knowledge.dismissSuggestion('kp_3f9a1c7e5b2d8046a1c3e5f7')

console.log(dismissed.status, dismissed.decidedAt)
```

**Notes**

- Needs `knowledge:write`. An unknown id is a 404 `knowledge_suggestion_not_found`, and one already accepted or dismissed a 409 `knowledge_suggestion_decided`.
- The SDK does not retry it. A 409 `knowledge_suggestion_decided` on your own second attempt after a lost response means the first one worked.

Also available in: API [`POST /knowledge/suggestions/{id}/dismiss`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-suggestions-id-dismiss); 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).

### `knowledge.listFlags()`

List the open duplicate and conflict flags

```ts
listFlags(options?: KnowledgeFlagListOptions): Promise<Array<KnowledgeFlagResource>>
```

Resolves the open warnings about pairs of knowledge 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 the 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 in one sentence. The AI looks for conflicts while the workspace setting `knowledgeLearning` is on, at most 200 times a day.

Change or delete one of the two items to settle a flag: a changed item is compared again once it is indexed, and the flags of a deleted item go with it. When the two are fine as they are, dismiss the flag with `dismissFlag`. A flag shows only to a caller who can see both items.

Scopes: `knowledge:read`.

**Parameters**

- `options.itemId` (`string`): Keeps the flags that name this knowledge item, on either side.
- `options.limit` (`number`): How many flags, from 1 to 100. The server defaults to 50.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`Array<KnowledgeFlagResource>`, each with `id`, `kind`, `status`, `sourceId`, `sourceTitle`, `otherSourceId`, `otherSourceTitle`, `detail`, `score` and `createdAt`. `score` is how close in meaning the two items are, from 0 to 1.

**Example**

```ts
const flags = await openemail.knowledge.listFlags()

for (const flag of flags) {
    console.log(flag.kind, flag.sourceTitle, flag.otherSourceTitle, flag.detail ?? '')
}
```

**Notes**

- Needs `knowledge:read`. Every item also carries `flags`, the number of open flags that name it, so `list` shows which items to look at.
- Only open flags are listed. A dismissed flag stays dismissed, and the same two items are not flagged for the same reason again.

Also available in: API [`GET /knowledge/flags`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-flags); 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).

### `knowledge.dismissFlag()`

Dismiss a duplicate or conflict flag

```ts
dismissFlag(id: string, options?: RequestScope): Promise<KnowledgeFlagResource>
```

Marks a flag `dismissed` when the two items are fine as they are, and resolves with it. 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.

Dismissing needs the reach to change items at the levels of both items: the whole workspace needs every address, a domain needs the whole domain, and an address needs that address.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the flag, `kf_` and 24 hex characters, as `listFlags` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeFlagResource` with `status: 'dismissed'`.

**Example**

```ts
const [flag] = await openemail.knowledge.listFlags({ itemId: 'kb_8c1f4a2b9d7e3f60a5c7b21d' })

if (flag) await openemail.knowledge.dismissFlag(flag.id)
```

**Notes**

- Needs `knowledge:write`. An unknown id, and a flag on an item the key cannot see, answer 404 `knowledge_flag_not_found`, and an item the key may not change is a 403 `knowledge_scope_not_reached`.
- Dismissing a flag twice leaves it the same way, so the SDK retries it on network failure and retryable statuses.

Also available in: API [`POST /knowledge/flags/{id}/dismiss`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-flags-id-dismiss); 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).

### `knowledge.listConnectors()`

List the knowledge connectors

```ts
listConnectors(options?: RequestScope): Promise<Array<KnowledgeConnectorResource>>
```

Resolves every connector at a level the caller can see, newest first. A connector keeps many web pages from one source in the knowledge base, each page as a link item at the connector's level: a site it crawls, a sitemap, an RSS or Atom feed, or a Zendesk help center. Each one says how many items it keeps, its status, when it last synced and when it syncs next.

Scopes: `knowledge:read`.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`Array<KnowledgeConnectorResource>`, each with `id`, `kind`, `scope`, `level`, `title`, `url`, `refreshDays`, `pageLimit`, `status`, `failure`, `items`, `lastSyncAt`, `nextSyncAt`, `createdAt` and `updatedAt`.

**Example**

```ts
const connectors = await openemail.knowledge.listConnectors()

for (const connector of connectors) console.log(connector.kind, connector.url, connector.items, connector.status)
```

**Notes**

- Needs `knowledge:read`. A key or an app limited to particular addresses sees the connectors at the whole workspace, at its addresses and at their domains.
- The items a connector keeps show in `list` too, each with `connectorId` naming it.

Also available in: API [`GET /knowledge/connectors`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-connectors); 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).

### `knowledge.addConnector()`

Keep the pages of a site, sitemap, feed or help center

```ts
addConnector(body: KnowledgeConnectorCreate, options?: RequestScope): Promise<KnowledgeConnectorResource>
```

Adds a connector at one level and resolves with it, `queued`. Its first sync starts within a minute, and every page it finds becomes a link item at the connector's level, read in the background like any other link.

`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, and syncs again every `refreshDays` days, 7 unless you say: new pages are added, changed ones are read again and the items of 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.

Scopes: `knowledge:write`.

**Parameters**

- `body.kind` (`KnowledgeConnectorKind`, required): What `url` is: `site`, `sitemap`, `feed` or `zendesk`.
- `body.url` (`string`, required): A public web address of at most 2,048 characters, kept as `https`: the page a site crawl starts from, the sitemap, the feed, or the address of the help center.
- `body.scope` (`string`): 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`.
- `body.title` (`string`): A name for the connector, at most 200 characters. Left out, the host and the kind, such as `acme.com (sitemap)`.
- `body.refreshDays` (`KnowledgeRefreshDays | null`): Sync again every 1, 7 or 30 days. Left out, 7. `null` syncs only when you call `syncConnector`.
- `body.pageLimit` (`number`): The most pages to keep, from 1 to 200. Left out, 25.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeConnectorResource` for the new connector, with `status: 'queued'` and `items: 0`.

**Example**

```ts
const docs = await openemail.knowledge.addConnector({
    kind: 'sitemap',
    url: 'https://acme.com/sitemap.xml',
    scope: '@acme.com',
    pageLimit: 100
})

console.log(docs.id, docs.status)
```

**Notes**

- Needs `knowledge:write`.
- An address that is not a public web address is a 422 `invalid_knowledge_connector`, and the same address at the same level a 409 `knowledge_connector_exists`. A `refreshDays` other than 1, 7, 30 or null is a 422 `invalid_knowledge_refresh`. A level that is not the workspace, one of its domains or one of its addresses is a 422 `invalid_knowledge_scope`, and a level outside what the key reaches is a 403 `knowledge_scope_not_reached`.
- A source that cannot be read after several tries ends `failed` with a `failure`. A sync that stopped at the plan allowance ends `ready` with `failure: 'over_allowance'`, and one that found nothing ends `ready` with `failure: 'empty'`.
- The SDK does not retry it. A second attempt after a lost response answers 409 `knowledge_connector_exists`, which means the first one worked.

Also available in: API [`POST /knowledge/connectors`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-connectors); 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).

### `knowledge.getConnector()`

Read one knowledge connector

```ts
getConnector(id: string, options?: RequestScope): Promise<KnowledgeConnectorResource>
```

Resolves one connector: its source, its level, how many items it keeps, its status, and when it last synced and syncs next. `status` is `queued` until a sync starts, `syncing` while it reads the source, `ready` once its pages are items, and `failed` with a `failure` when the source could not be read after several tries.

Scopes: `knowledge:read`.

**Parameters**

- `id` (`string`, required): The id of the connector, `kc_` and 24 hex characters, as `listConnectors` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeConnectorResource`, the fields `listConnectors` returns for each connector.

**Example**

```ts
const connector = await openemail.knowledge.getConnector('kc_5d2e8f1a3c7b9064e2a4c6f8')

console.log(connector.status, connector.items, connector.nextSyncAt)
```

**Notes**

- Needs `knowledge:read`. An unknown id, and a connector at a level the key cannot see, answer 404 `knowledge_connector_not_found`.

Also available in: API [`GET /knowledge/connectors/{id}`](https://openemail.uk/docs/api/reference/knowledge#get-knowledge-connectors-id); 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).

### `knowledge.updateConnector()`

Change a knowledge connector

```ts
updateConnector(id: string, patch: KnowledgeConnectorPatch, options?: RequestScope): Promise<KnowledgeConnectorResource>
```

Changes the title of a connector, its level, how often it syncs or the most pages it keeps, and resolves with it as it is now. Give at least one field. Moving it to another level moves its items with it, and they are indexed again there. A new `refreshDays` counts from the last sync, and a new `pageLimit` applies from the next sync.

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 a connector needs that reach at both levels.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the connector, `kc_` and 24 hex characters, as `listConnectors` returns it.
- `patch.title` (`string`): A new name, at most 200 characters.
- `patch.scope` (`string`): The level to move it and its items to: an empty string for the whole workspace, `@` and a domain, or one address.
- `patch.refreshDays` (`KnowledgeRefreshDays | null`): Sync every 1, 7 or 30 days. `null` syncs only when you call `syncConnector`.
- `patch.pageLimit` (`number`): The most pages to keep, from 1 to 200.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeConnectorResource` as it is now.

**Example**

```ts
const connector = await openemail.knowledge.updateConnector('kc_5d2e8f1a3c7b9064e2a4c6f8', {
    refreshDays: 1,
    pageLimit: 150
})

console.log(connector.nextSyncAt)
```

**Notes**

- Needs `knowledge:write`. An empty patch is a 422 `invalid_parameter`, and a `refreshDays` other than 1, 7, 30 or null a 422 `invalid_knowledge_refresh`. Moving it to a level that already has a connector for the same address is a 409 `knowledge_connector_exists`.
- Retried automatically on network failure and retryable statuses, since the same patch applied twice leaves the same connector.

Also available in: API [`PATCH /knowledge/connectors/{id}`](https://openemail.uk/docs/api/reference/knowledge#patch-knowledge-connectors-id); 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).

### `knowledge.deleteConnector()`

Delete a knowledge connector and its items

```ts
deleteConnector(id: string, options?: RequestScope): Promise<DeletedKnowledgeConnectorResource>
```

Removes a connector with every item it added to the knowledge base, and the AI stops using them at once. There is no undo. Links you added yourself stay, even when the connector found the same pages.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the connector, `kc_` and 24 hex characters, as `listConnectors` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`DeletedKnowledgeConnectorResource`, `{ object: 'knowledge_connector', id, deleted: true }`.

**Example**

```ts
const removed = await openemail.knowledge.deleteConnector('kc_5d2e8f1a3c7b9064e2a4c6f8')

console.log(removed.deleted)
```

**Notes**

- Needs `knowledge:write`, and reach over the level of the connector. An unknown id is a 404 `knowledge_connector_not_found`.
- The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.

Also available in: API [`DELETE /knowledge/connectors/{id}`](https://openemail.uk/docs/api/reference/knowledge#delete-knowledge-connectors-id); 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).

### `knowledge.syncConnector()`

Sync a knowledge connector now

```ts
syncConnector(id: string, options?: RequestScope): Promise<KnowledgeConnectorResource>
```

Queues a sync that starts within a minute, whatever the schedule says, clears any `failure` and resolves with the connector, back at `queued`. Use it after the source changed, or to try again after a failure. Like a scheduled sync, it adds new pages, reads changed ones again and removes the items of pages that are gone.

Scopes: `knowledge:write`.

**Parameters**

- `id` (`string`, required): The id of the connector, `kc_` and 24 hex characters, as `listConnectors` returns it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeConnectorResource`, queued to sync.

**Example**

```ts
const connectors = await openemail.knowledge.listConnectors()

for (const connector of connectors.filter((entry) => entry.status === 'failed')) {
    await openemail.knowledge.syncConnector(connector.id)
}
```

**Notes**

- Needs `knowledge:write`, and reach over the level of the connector. An unknown id is a 404 `knowledge_connector_not_found`.
- Queuing a sync twice leaves it the same way, so the SDK retries it on network failure and retryable statuses.

Also available in: API [`POST /knowledge/connectors/{id}/sync`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-connectors-id-sync); 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).

### `knowledge.draftFromThread()`

Draft a knowledge note from a conversation

```ts
draftFromThread(body: KnowledgeDraftInput, options?: RequestScope): Promise<KnowledgeDraftResource>
```

The AI reads a conversation and drafts 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: the draft comes back with a `title`, a `body` in Markdown and a `scope` it suggests, and you keep it, changed as you like, with `createNote` and the same `threadId`.

`scope` suggests the domain the conversation arrived at when the caller may add items there, otherwise the whole workspace or the address itself. Each draft counts as one AI action.

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

**Parameters**

- `body.threadId` (`string`, required): The conversation, by the id `threads.list` gives it.
- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Overrides the client API key for this call only.

**Returns**

`KnowledgeDraftResource`, `{ object: 'knowledge_draft', title, body, scope, threadId }`.

**Example**

```ts
const draft = await openemail.knowledge.draftFromThread({ threadId: 'CAHk7pQ2x9LmZ4-mail.example.com' })

const note = await openemail.knowledge.createNote({
    scope: draft.scope,
    title: draft.title,
    body: draft.body,
    threadId: draft.threadId
})

console.log(note.id, note.threadId)
```

**Notes**

- Needs `knowledge:write` and `threads:read`.
- A conversation the key cannot read is a 404 `knowledge_thread_not_found`. One with no facts worth keeping is a 422 `knowledge_nothing_to_save`, and a 503 `knowledge_ai_unavailable` means the AI did not answer, so try again in a moment.
- The SDK does not retry it, because every attempt is an AI action.

Also available in: API [`POST /knowledge/drafts`](https://openemail.uk/docs/api/reference/knowledge#post-knowledge-drafts); 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).
