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

# Knowledge Bases API

> Document storage + semantic search that powers retrieval-augmented generation for AI agents.

# Knowledge Bases API

Upload documents (PDFs, Word, plain text, web pages) into per-tenant vector stores. AI agents query these stores at run time to ground their responses. Each knowledge base is an independent index — you'd typically have one per topic ("Product manuals", "HR policies", "Refund flow").

**Base path:** `/api/v1/knowledge-bases`

**Authentication:** API key (`X-API-Key`) or session JWT.

**Upload limits:** 10 MB per document. PDF, DOCX, TXT, MD, and HTML supported.

## Knowledge bases

| Method   | Path                           | Purpose                       |
| -------- | ------------------------------ | ----------------------------- |
| `GET`    | `/api/v1/knowledge-bases`      | List knowledge bases          |
| `POST`   | `/api/v1/knowledge-bases`      | Create a knowledge base       |
| `GET`    | `/api/v1/knowledge-bases/{id}` | Get a knowledge base          |
| `PUT`    | `/api/v1/knowledge-bases/{id}` | Update name / description     |
| `DELETE` | `/api/v1/knowledge-bases/{id}` | Delete (purges all documents) |

## Documents

| Method   | Path                                                           | Purpose                                                   |
| -------- | -------------------------------------------------------------- | --------------------------------------------------------- |
| `GET`    | `/api/v1/knowledge-bases/{id}/documents`                       | List documents                                            |
| `POST`   | `/api/v1/knowledge-bases/{id}/documents`                       | Upload (multipart)                                        |
| `DELETE` | `/api/v1/knowledge-bases/{id}/documents/{docId}`               | Remove a document                                         |
| `POST`   | `/api/v1/knowledge-bases/{id}/documents/{docId}/retry`         | Retry a failed indexing job                               |
| `POST`   | `/api/v1/knowledge-bases/{id}/documents/{docId}/approve`       | Approve a document pending review                         |
| `POST`   | `/api/v1/knowledge-bases/{id}/documents/{docId}/reject`        | Reject a document pending review                          |
| `GET`    | `/api/v1/knowledge-bases/{id}/documents/{docId}/versions`      | List a document's version history                         |
| `GET`    | `/api/v1/knowledge-bases/{id}/documents/{docId}/versions/diff` | Diff two versions of a document                           |
| `POST`   | `/api/v1/knowledge-bases/{id}/documents/{docId}/rollback`      | Restore a retained earlier version                        |
| `PATCH`  | `/api/v1/knowledge-bases/{id}/documents/{docId}/publication`   | Publish or unpublish a document on the public help center |

Indexing happens asynchronously. A document goes through `processing` → `ready` (or `failed`). Poll `GET /:id/documents` to track status, and re-run a failed job with `POST /:id/documents/{docId}/retry`.

Documents that require moderation move through a publish lifecycle: they start as `pending`, then become `approved` or `rejected`. While a document sits in `pending` its chunks are not retrievable by agents. Approve it with `POST /:id/documents/{docId}/approve` to promote it to ground-truth and start indexing, or reject it with `POST /:id/documents/{docId}/reject` to keep it out of retrieval. Both accept an optional body `{ "notes": "…" }` to record a reviewer note on the document, and both require the `knowledge:write` scope.

Every re-upload of a document retains the superseded copy as an immutable snapshot. `GET /:id/documents/{docId}/versions` returns the current head plus every retained snapshot so you can audit how the RAG ground-truth has changed over time.

Compare any two retained versions with `GET /:id/documents/{docId}/versions/diff?from={n}&to={m}` — it returns added / removed / unchanged line counts plus unified-style hunk lines (`+` added, `-` removed, ` ` context). A version whose content was not retained (it exceeded the retention size cap) returns `422`.

Restore an earlier version with `POST /:id/documents/{docId}/rollback` (body `{ "version": n }`). Rollback is non-destructive — the target version's content is re-uploaded as a **new** head version (the current head is snapshotted into history first), so the operation is fully reversible. It returns `202` with the freshly-minted head document.

### Public help-center publication

Publish a document to your public help center with `PATCH /:id/documents/{docId}/publication`. This toggles whether a single document is exposed on the public help surface, independent of its indexing status for agents.

| Field       | Type    | Description                                                                                                                                                                                         |
| ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `is_public` | boolean | **Required.** `true` exposes the document on the public help center; `false` removes it.                                                                                                            |
| `slug`      | string  | URL segment the public page routes by. Lowercase letters, digits, and hyphens only (max 200 chars). **Required when `is_public` is `true`** — the public surface cannot resolve a page without one. |
| `summary`   | string  | Optional public-facing summary (max 2000 chars).                                                                                                                                                    |

The PATCH verb lets the operator UI flip publication with a partial body without re-stating the slug on every change. This is a write action — it requires the `knowledge:write` scope and an admin, owner, or developer seat, and both publishing and unpublishing are audit-logged, because setting `is_public=true` exposes the article to the open web. It returns the updated document.

```bash theme={null}
curl -X PATCH https://api.orbit.devotel.io/api/v1/knowledge-bases/kb_abc/documents/doc_123/publication \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "is_public": true, "slug": "international-refunds", "summary": "How refunds work for international orders." }'
```

## Freshness

| Method | Path                                     | Purpose                                  |
| ------ | ---------------------------------------- | ---------------------------------------- |
| `GET`  | `/api/v1/knowledge-bases/{id}/staleness` | Freshness scorecard across all documents |

Stale ground-truth is a leading cause of wrong agent answers. `GET /:id/staleness` scans every document in a knowledge base and classifies each one by age into a `fresh`, `stale`, or `critical` bucket, so you can find and re-verify outdated content before agents cite it.

A document's age is measured from its last operator verification (`last_verified_at`) if present, otherwise its last update (`updated_at`). A document is `stale` once its age reaches the threshold, `critical` once it reaches twice the threshold, and `fresh` below it. A document with no verifiable timestamp is reported as `critical`. The default threshold is 90 days; override it for one call with `?default_threshold_days={n}` (1–3650). A per-document threshold, when set, always takes precedence over the default.

The response is a scorecard:

| Field                                               | Description                                                                                                                                                                                          |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `knowledge_base_id`                                 | The scanned knowledge base.                                                                                                                                                                          |
| `totals.fresh` / `totals.stale` / `totals.critical` | Document counts per bucket.                                                                                                                                                                          |
| `totals.documents_scanned`                          | Total documents classified.                                                                                                                                                                          |
| `totals.never_verified`                             | Documents never operator-verified.                                                                                                                                                                   |
| `attention_required`                                | Documents not in the `fresh` bucket, oldest-first. Each entry carries `id`, `name`, `type`, `status`, `bucket`, `age_days`, `threshold_days`, `last_verified_at`, `last_cited_at`, and `updated_at`. |
| `default_threshold_days`                            | The threshold applied to documents without a per-document override.                                                                                                                                  |
| `scanned_at`                                        | When the scan ran (ISO-8601).                                                                                                                                                                        |

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/knowledge-bases/kb_abc/staleness?default_threshold_days=30 \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

## Connectors

A connector binds a knowledge base to an external content source (Notion, Confluence, Google Drive, SharePoint, or Zendesk) and keeps it in sync.

### Connector management

| Method   | Path                                                         | Purpose                                   |
| -------- | ------------------------------------------------------------ | ----------------------------------------- |
| `GET`    | `/api/v1/knowledge-bases/{id}/connectors`                    | List a knowledge base's connectors        |
| `POST`   | `/api/v1/knowledge-bases/{id}/connectors`                    | Add a connector to a knowledge base       |
| `PATCH`  | `/api/v1/knowledge-bases/{id}/connectors/{connectorId}`      | Update a connector                        |
| `DELETE` | `/api/v1/knowledge-bases/{id}/connectors/{connectorId}`      | Remove a connector                        |
| `POST`   | `/api/v1/knowledge-bases/{id}/connectors/{connectorId}/sync` | Trigger an immediate sync for a connector |

Listing connectors needs `knowledge:read`. Adding, updating, deleting, and syncing a connector each require `knowledge:write` (admin, owner, or developer seat), since they bind a knowledge base to — or refresh it from — an external source. `POST /:id/connectors/{connectorId}/sync` runs the connector's sync immediately instead of waiting for the next scheduled refresh.

### Drift report

| Method | Path                                                  | Purpose                                       |
| ------ | ----------------------------------------------------- | --------------------------------------------- |
| `GET`  | `/api/v1/knowledge-bases/{id}/connector-drift-report` | Content-drift scorecard for source connectors |

When a knowledge base syncs from external sources, content can drift from the cached copy your agents ground on. `GET /:id/connector-drift-report` reports which sources have diverged since their last successful sync, so you can trigger a refresh before agents answer from stale content.

## Search

| Method | Path                                         | Purpose                                 |
| ------ | -------------------------------------------- | --------------------------------------- |
| `POST` | `/api/v1/knowledge-bases/{id}/search`        | Semantic search across documents        |
| `GET`  | `/api/v1/knowledge-bases/{id}/search-config` | Read the retrieval re-ranking config    |
| `PUT`  | `/api/v1/knowledge-bases/{id}/search-config` | Replace the retrieval re-ranking config |

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/knowledge-bases/kb_abc/search \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "query": "How do refunds work for international orders?", "limit": 4 }'
```

### Re-ranking configuration

Each knowledge base carries a re-ranking config that controls how retrieved chunks are scored and filtered before they ground an agent answer. The config applies to both the agent retrieval path and the `POST /:id/search` endpoint for that knowledge base.

`GET /api/v1/knowledge-bases/{id}/search-config` returns the current config. Reading requires the `knowledge:read` scope.

`PUT /api/v1/knowledge-bases/{id}/search-config` replaces it. Every field has a no-op default, so a `PUT` with `{}` resets the knowledge base to legacy raw-similarity ordering. Writing requires the `knowledge:write` scope and an owner, admin, or developer role.

| Field                    | Type      | Default | Range         | Effect                                                                                                    |
| ------------------------ | --------- | ------- | ------------- | --------------------------------------------------------------------------------------------------------- |
| `min_score`              | number    | `0`     | 0–1           | Drop chunks whose raw vector similarity is below this floor.                                              |
| `recency_boost`          | number    | `0`     | 0–5           | Recency multiplier strength. `0` disables it; fresher documents are boosted up to ×(1 + `recency_boost`). |
| `recency_half_life_days` | number    | `30`    | 1–3650        | Half-life (in days) of the recency decay applied by `recency_boost`.                                      |
| `source_weights`         | object    | `{}`    | values 0–20   | Map of source label → score multiplier. Keys are matched case-insensitively.                              |
| `include_categories`     | string\[] | `[]`    | ≤ 200 entries | Allow-list of categories. Empty allows all.                                                               |
| `exclude_categories`     | string\[] | `[]`    | ≤ 200 entries | Deny-list of categories.                                                                                  |

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/knowledge-bases/kb_abc/search-config \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
        "min_score": 0.6,
        "recency_boost": 1.5,
        "recency_half_life_days": 14,
        "source_weights": { "product-manual": 2, "community-forum": 0.5 },
        "include_categories": ["refunds", "shipping"],
        "exclude_categories": ["internal"]
      }'
```

## Retrieval tuning (operator)

When an AI agent grounds a reply, the executor retrieves KB chunks for that turn (see [AI Agents API](/api-reference/agents)). Two platform environment variables control how many chunks each agent turn retrieves and how aggressively low-relevance chunks are filtered. They are platform-wide defaults set by the operator (not per-request), and matter most for tenants with noisy knowledge bases:

| Variable                     | Default | Range | Effect                                                                                                                                                          |
| ---------------------------- | ------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DEVOTEL_KB_TOP_K`           | `5`     | 1–50  | Chunks retrieved per agent turn. Bigger = more context but more tokens billed per turn; smaller = tighter signal and faster turns.                              |
| `DEVOTEL_KB_SCORE_THRESHOLD` | `0.7`   | 0–1   | Cosine-similarity cutoff; chunks scoring below this are dropped. Raise it to suppress weakly-related noise; lower it if relevant chunks are being filtered out. |

These tune the agent retrieval path only. The `POST /api/v1/knowledge-bases/{id}/search` endpoint above takes its own per-request `limit` and is unaffected by these variables.

## See also

* [AI Agents API](/api-reference/agents) — attach a knowledge base to an agent
* [AI API → embedded KB](/api-reference/ai#knowledge-base) — single-doc utility for ad-hoc reasoning
