Canonical page: https://docs.singlebase.io/chat

# Chat

Build assistants that remember. `chat.*` operations create and continue persisted chats grounded in your documents and data, and manage their history.

## Overview

**Conversation** powers Chat with Documents. Each chat keeps its messages, knowledge sources, and attachments, so users and agents can pick up where they left off.

**Key features:**
- **Persisted chats** - History, titles, and bookmarks for chats and messages
- **Chat with Documents** - Answers grounded in your documents and records, with citations
- **Retrieval** - VectorDB embeddings and vector search, FTS5 keyword search, and hybrid retrieval through [docsets](#docsets)
- **Attachments** - Bring in uploaded files, URLs, or inline text
- **Modes** - Free chat, cited answers (RAG), or strict knowledge-base answers
- **Models** - Choose a model available in the deployed catalog

**Use cases:** Shopping and support assistants, document Q&A, onboarding guides, internal knowledge bots

**On your website:** The [Chat Box](https://singlebase.io/components/chat-box/) web component embeds Chat with Documents in your site.

**Access:** `chat.*` operations are public: a valid project key is enough. Chats are scoped to the project and the user in the bearer token.

::: warning
Without a bearer token, a chat is not tied to any user. In browser and mobile apps, send the signed-in user's ID token with every `chat.*` request.
:::

For one-off answers that are not saved, use [`chat.ask`](#chat-ask). It takes the same retrieval, attachments, and modes.

---

## Operations

| Operation | Description | Required payload |
|---|---|---|
| `chat.ask` | Ask without saving a conversation | `message` |
| `chat.prepare` | Prepare context and starter questions | None |
| `chat.send` | Start a conversation or continue one | `message` |
| `chat.list` | List conversations | None |
| `chat.get` | Get a conversation and its messages | Exactly one of `chat_id`/`_id` or `key` |
| `chat.update` | Rename or bookmark a conversation | `chat_id`, a change |
| `chat.bookmark` | Bookmark or unbookmark a conversation | `chat_id`, `bookmarked` |
| `chat.delete` | Delete a conversation | `chat_id` |
| `chat.bookmark_message` | Bookmark or unbookmark one message | `chat_id`, `message_id`, `bookmarked` |
| `chat.delete_message` | Delete one message | `chat_id`, `message_id` |
| `chat.remove_attachment` | Remove a saved attachment from a conversation | `chat_id`, `attachment_id` |

`chat_id` also accepts the alias `_id`.

---

## chat.ask

Get a single answer. Nothing is saved, so there is no history to manage.

```json
{
  "operation": "chat.ask",
  "payload": {
    "message": "Explain an HTTP 429 response in one sentence."
  }
}
```

**Example - Answer from a docset, by meaning:**
```json
{
  "operation": "chat.ask",
  "payload": {
    "message": "Something for a laptop and a daily commute",
    "mode": "rag",
    "retrieval": [{ "source": "docset", "ids": "products" }]
  }
}
```

**Parameters:**

| Field | Description |
|---|---|
| `message` | The question (required) |
| `system_message` | System instructions |
| `mode` | `chat` (default), `rag`, or `kb`. See [Modes](/chat.md#modes) |
| `retrieval` | Knowledge sources, such as [docsets](/chat.md#docsets) |
| `attachments` | Up to 5 [attachments](/chat.md#attachments). Always one turn |
| `followups` | `true`, or 1 to 5, to suggest follow-up questions |
| `model`, `params` | Model and model parameters |
| `format` | `text`, `json`, or `markdown` |

Retrieval and attachments apply to this request only. To keep a thread going, use [`chat.send`](/chat.md#chat-send).

---

## chat.send

Send a message. Without `chat_id`, a new conversation starts. With `chat_id`, the conversation continues.

**Example - Start a conversation:**
```json
{
  "operation": "chat.send",
  "payload": {
    "message": "Help me plan an API integration.",
    "title": "Integration planning",
    "system_message": "Be concise."
  }
}
```

The response includes the chat's `_id`.

**Example - Continue it:**
```json
{
  "operation": "chat.send",
  "payload": {
    "chat_id": "chat_123",
    "message": "What should I build first?"
  }
}
```

**Parameters:**

| Field | Description |
|---|---|
| `message` | The user's message (required) |
| `chat_id` | Continue an existing chat. Alias `_id` |
| `system_message` | System instructions |
| `title` | Chat title |
| `mode` | `chat` (default), `rag`, or `kb`. See [Modes](#modes) |
| `retrieval` | Knowledge sources. See [Retrieval](#retrieval) |
| `attachments` | Up to 5 attachments. See [Attachments](#attachments) |
| `followups` | `true`, or 1 to 5, to suggest follow-up questions. Default `false` |
| `include_messages` | Include the message history in the response |
| `model`, `params` | Model and model parameters |
| `format` | `text`, `json`, or `markdown` |
| `metadata` | Custom chat metadata |

### Modes

`mode` controls how the answer uses retrieval sources and attachments.

| Mode | Behavior |
|---|---|
| `chat` | Sources may help, and the model can also use general knowledge. Default |
| `rag` | The model prefers and cites sources. It may use general knowledge when sources don't answer, and says so |
| `kb` | The model answers only from sources and says when the answer isn't there. Requires at least one source or attachment |

Use `kb` when answers must stay inside your content.

---

## Retrieval

Ground answers in your data with `retrieval`. Each entry has a `source`.

Retrieval sent to `chat.send` is saved on the chat and applies to later turns until you replace it. Send `retrieval: []` to clear it.

### Docsets

A **docset** is a named knowledge base over your project collections. It is how agents and apps query your data by meaning or by keyword. Project admins create docsets in the console; apps and agents reference them by slug, without seeing collection names or filters.

**What a docset defines:**

| Setting | Description |
|---|---|
| `slug`, `name` | How you reference it, for example `products` |
| `collections` | 1 to 10 collections to search |
| `search` | `kdb` for FTS5 full-text search (default), or `vector` for vector retrieval with full-text fallback for other collections |
| `filter`, `document_ids` | Narrow the searchable records, for example `{"status": "published"}` |
| `limit` | Passages per answer, 1 to 20. Default `6` |
| `acl` | Who may use it: `admin`, `user` (default), `agent`, or `nobody` |

**Example - A shopping assistant searching by meaning:**
```json
{
  "operation": "chat.send",
  "payload": {
    "message": "Something for a laptop and a daily commute",
    "mode": "rag",
    "retrieval": [{ "source": "docset", "ids": "products" }]
  }
}
```

**Example - A support assistant answering only from knowledge:**
```json
{
  "operation": "chat.send",
  "payload": {
    "message": "How do I cancel my plan?",
    "mode": "kb",
    "retrieval": [
      { "source": "docset", "ids": ["support", "billing"] }
    ]
  }
}
```

**Rules:**
- `ids` takes one slug or ID, or a list of up to 5.
- Docsets must exist, be enabled, and allow the caller. Agent keys count as `agent`.
- Send IDs only. Embedded `docsets` definitions are rejected (`INVALID_RETRIEVAL`).
- A missing, disabled, or inaccessible docset returns `DOCSET_NOT_FOUND` (HTTP 422).

### Search and hybrid retrieval

Singlebase supports three retrieval paths for chat:

| Search path | How it finds context |
|---|---|
| **FTS5 full-text search** | `search: "kdb"` docsets search collection text for words and phrases through the database full-text query path |
| **VectorDB embeddings and vector search** | `search: "vector"` docsets embed the question and search the project's indexed document chunks by similarity; Smart Bucket file content is searched through its file vectors |
| **Hybrid retrieval** | A vector docset combines vector results with full-text results from collections that have neither collection vector indexing nor Smart Bucket file sources. Multiple docsets can also combine keyword and semantic results in the same answer |

The console labels the vector docset option **Hybrid search**. Its API value remains `"vector"`; docset `search` accepts only `"kdb"` or `"vector"`. Vector mode uses full-text fallback for the other collections described above; it does not automatically run both searches over every indexed collection. Retrieved passages are combined as model context; there is no configurable keyword/vector weighting parameter in this API.

For example, create two accessible docsets in the console: `support-keywords` with `search: "kdb"`, and `support-semantic` with `search: "vector"` over your indexed support collection. Then combine them:

```json
{
  "operation": "chat.ask",
  "payload": {
    "message": "How do I fix error E104 when uploading a document?",
    "mode": "kb",
    "retrieval": [
      { "source": "docset", "ids": ["support-keywords", "support-semantic"] }
    ]
  }
}
```

Keyword retrieval finds the exact error code, while vector retrieval can find related troubleshooting text with different wording. Both docsets must exist and permit the caller. Collection embeddings must be available for vector retrieval; see [Data overview](/data.md#overview).

### Sources by key type

| Caller | Allowed sources |
|---|---|
| Web key (`wk_`) | `docset`, `attachments`, `docs`, `json`, `csv`, `data` |
| Server or agent key | All of the above, plus `kdb`, `vector`, `s3`, `generate` |

Raw collections, vector indexes, storage objects, and generated prompts need a trusted key. Public apps should use docsets.

`type` is accepted as an alias for `source`. If both are sent, they must match.

---

## Attachments

Attach up to 5 items to a message.

```json
{
  "operation": "chat.send",
  "payload": {
    "message": "Compare these documents.",
    "mode": "rag",
    "attachments": [
      {
        "type": "content",
        "name": "notes.txt",
        "mime": "text/plain",
        "content": "Version 2 adds file uploads and token rotation."
      },
      {
        "type": "file_id",
        "file_id": "7b21f51e730d40d0b0e373ef720e43d5",
        "name": "contract.pdf"
      },
      {
        "type": "url",
        "url": "https://example.com/terms",
        "save_attachment": false
      }
    ]
  }
}
```

| Type | Required field | Optional fields | Rules |
|---|---|---|---|
| `content` | `content` | `name`, `mime`, `size`, `save_attachment` | Up to 512,000 UTF-8 bytes |
| `file_id` | `file_id` | `name`, `save_attachment` | A [file](/files.md) the user owns. Admins can use any project file |
| `url` | `url` | `name`, `save_attachment` | HTTPS only |

**Behavior:**
- `save_attachment` defaults to `true`: the attachment stays available on later turns. Set it to `false` for one turn only.
- The response may include `data.attachments` with each attachment's `id`, `type`, `name`, `mime`, `size`, `saved`, and `status`.
- Extraction failures may appear as attachment-level errors. Payload validation and file ownership failures reject the request before the turn runs; `FILE_FORBIDDEN` is not an attachment that can simply be skipped.

---

## chat.prepare

Prepare context before the first message, and optionally generate starter questions. Use the returned `_id` in a later `chat.send`.

```json
{
  "operation": "chat.prepare",
  "payload": {
    "title": "Product support",
    "mode": "kb",
    "retrieval": [{ "source": "docset", "ids": "support" }],
    "starters": 3
  }
}
```

The `support` docset must exist, be enabled, and allow your caller. `starters` accepts `true`, `false`, or a count from 1 to 6. `refresh` can refresh starter generation; the response includes the prepared chat's state.

### Chat keys

A `key` is a per-user application identifier, such as `support-widget`. It needs a signed-in user. `chat.send` and `chat.prepare` can use it to address a chat, and `chat.get` accepts exactly one of `key` or a chat ID. Keys are 1 to 128 characters, start with a letter or digit, and allow letters, digits, `.`, `_`, `:`, and `-`. `chat.ask` refuses `key` because it does not persist a chat.

---

## Manage Conversations

Use the same credentials that created the chat.

### chat.list

```json
{
  "operation": "chat.list",
  "payload": {
    "bookmarked": true,
    "limit": 20,
    "offset": 0
  }
}
```

All fields are optional. Lists chats without their messages, most recently modified first.

### chat.get

```json
{
  "operation": "chat.get",
  "payload": { "chat_id": "chat_123" }
}
```

Returns the chat with its active messages, saved `attachments`, and `mode`.

### chat.update

```json
{
  "operation": "chat.update",
  "payload": {
    "chat_id": "chat_123",
    "title": "API integration checklist",
    "bookmarked": true
  }
}
```

Send `title`, `bookmarked`, or both.

### chat.bookmark

```json
{
  "operation": "chat.bookmark",
  "payload": { "chat_id": "chat_123", "bookmarked": true }
}
```

`bookmarked` is required. Use `false` to remove the bookmark.

### chat.delete

```json
{
  "operation": "chat.delete",
  "payload": { "chat_id": "chat_123" }
}
```

Deletes the chat and all its messages.

### chat.bookmark_message

```json
{
  "operation": "chat.bookmark_message",
  "payload": {
    "chat_id": "chat_123",
    "message_id": "msg_456",
    "bookmarked": true
  }
}
```

The message must belong to the chat.

### chat.delete_message

```json
{
  "operation": "chat.delete_message",
  "payload": { "chat_id": "chat_123", "message_id": "msg_456" }
}
```

The message must belong to the chat.

### chat.remove_attachment

```json
{
  "operation": "chat.remove_attachment",
  "payload": { "chat_id": "chat_123", "attachment_id": "att_789" }
}
```

Removes a saved attachment from the chat. The underlying file is not deleted; use [`files.delete`](/files.md#files-delete) for that.

---

## Common Errors

| Message | Meaning |
|---|---|
| `INVALID_PAYLOAD` | The payload does not match the operation |
| `KB_SOURCE_REQUIRED` | `kb` mode has no retrieval source or attachment |
| `RETRIEVAL_SOURCE_FORBIDDEN` | A web-key caller used a server-only source |
| `RETRIEVAL_SOURCE_MISMATCH` | `source` and `type` disagree |
| `DOCSET_NOT_FOUND` | A docset is missing, disabled, or not available to the caller |
| `INVALID_RETRIEVAL` | Invalid docset IDs, or the client sent docset definitions |
| `INVALID_QUERY_FOR_SOURCE` | The retrieval query does not fit its source |
| `ATTACHMENT_LIMIT` | More than 5 attachments, or too many on the chat |
| `ATTACHMENT_TOO_LARGE` | Inline or extracted attachment content is too large |
| `FILE_FORBIDDEN` | The user does not own the attached file |
| `LLM_REQUEST_FAILED` | The LLM service failed (HTTP 502) |

Validation errors from the LLM service return HTTP 422 with the service's message. See [Responses](/api.md#responses) for the error envelope.

---

## Next Steps

- [LLM](/llm.md) - One-off answers, generation, and embeddings
- [Files](/files.md) - Upload documents to use as attachments
- [Data](/data.md) - Store the content your docsets search
- [Agents](/agents.md) - Give AI agents scoped chat permissions

## Compatibility

The former `conversation.*` namespace has been removed. Deprecated `llm.*` chat
aliases remain available.

Vector docsets use the project index, combining indexed collection fields and
attached Smart Bucket file text with full-text fallback. File text is embedded
only once under `__files`. See [Data overview](/data.md#overview).
