> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.voicebip.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.voicebip.com/_mcp/server.

# Knowledge Base Deep-Dive

> Everything the KB primitive does on its own — ingest documents, poll status, tune retrieval, and query for relevant chunks *without* a call. RAG search as a standalone capability.

**What you build:** a reusable retrieval layer. This page treats the Knowledge Base as a primitive in its own right — how ingestion works, how to poll it, how retrieval is tuned, and how to run pure RAG queries from your own code (no voice or messaging turn involved). If you just want a KB attached to a support agent, start at [Inbound support + KB](/use-cases/inbound-support-kb); come here to understand the machinery.

**Who it's for:** developers building BYOM agents that do their own retrieval, teams debugging "why didn't the agent use my doc," and anyone who wants a hosted vector-search endpoint over their content.

## The two ways to use a KB

| Mode                  | Retrieval                                                                  | Your code                              |
| --------------------- | -------------------------------------------------------------------------- | -------------------------------------- |
| **Hosted-AI agent**   | Automatic on every voice/messaging turn (`knowledge_base_id` on the agent) | None                                   |
| **BYOM / standalone** | You call `POST /v1/knowledge-bases/{id}/query`                             | You inject chunks into your own prompt |

## Step 1 — Create a KB

```bash
curl -X POST https://api.voicebip.com/v1/knowledge-bases \
  -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
  -d '{ "name": "Support FAQ", "description": "Billing, refunds, delivery" }'
```

```json
{ "id": "kb_8sd2k1fapvq3", "document_count": 0, "chunk_count": 0, "created_at": "2026-07-02T10:00:00Z" }
```

## Step 2 — Add documents

Two source types. **Files** (`pdf`/`docx`/`txt`) use a three-step flow; **URLs** ingest immediately.

### File upload (register → PUT → finalize)

```bash
# 1. register — returns a presigned upload_url (valid ~10 min)
curl -X POST https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/documents \
  -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
  -d '{ "name": "refund-policy.pdf", "source_type": "pdf", "size_bytes": 248120 }'
# → { "id": "doc_4kq…", "status": "pending", "upload_url": "https://storage…" }

# 2. PUT the bytes with the matching Content-Type
curl -X PUT "<upload_url>" -H "Content-Type: application/pdf" \
  --data-binary @refund-policy.pdf

# 3. finalize — kicks off chunk → embed → index (idempotent)
curl -X POST https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/documents/doc_4kq…/complete \
  -H "Authorization: Bearer pk_xxx"
```

| source_type | Content-Type for the PUT                                                  |
| ----------- | ------------------------------------------------------------------------- |
| `pdf`       | `application/pdf`                                                         |
| `docx`      | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` |
| `txt`       | `text/plain`                                                              |

### URL source (one step)

```bash
curl -X POST https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/documents \
  -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
  -d '{ "name": "Pricing page", "source_type": "url", "source_url": "https://acme.example/pricing" }'
```

> **Note**
>
> File uploads need object storage configured on the deployment; if it isn't, document creation returns `503`. URL sources don't. Image-only PDFs (no text layer) can't be extracted and end up `failed`.

## Step 3 — Poll to `ready`

Ingestion is async. Only `ready` documents are searched:

```bash
curl https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/documents/doc_4kq… \
  -H "Authorization: Bearer pk_xxx"
```

| Status       | Meaning                                                    |
| ------------ | ---------------------------------------------------------- |
| `pending`    | Registered, awaiting upload + finalize (file sources)      |
| `processing` | Extracting text, chunking, embedding                       |
| `ready`      | Indexed and live; `chunk_count` populated                  |
| `failed`     | `error_message` says why (unreadable PDF, unreachable URL) |

## Step 4 — Query it (RAG without a call)

This is the standalone superpower — vector search over your content from any code path:

```bash
curl -X POST https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/query \
  -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
  -d '{ "query": "How long do refunds take?", "top_k": 5 }'
```

```json
{
  "query": "How long do refunds take?",
  "count": 2,
  "chunks": [
    { "content": "Refunds are processed within 5–7 business days of approval…", "source": "refund-policy.pdf", "score": 0.83 },
    { "content": "For card payments, the refund appears on your statement…", "source": "refund-policy.pdf", "score": 0.71 }
  ]
}
```

* `top_k` — 1–10, default 5.
* `score` — cosine similarity (0–1, higher = more relevant).
* Below-threshold chunks are dropped, so a query with no good match returns `count: 0` and `200` (not `404`).
* `query` is capped at 4096 characters.

### Using it in a BYOM turn

```js
// inside your BYOM webhook handler
const { chunks } = await fetch(
  `https://api.voicebip.com/v1/knowledge-bases/${kbId}/query`,
  { method: "POST",
    headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ query: callerMessage, top_k: 3 }) }
).then(r => r.json());

const context = chunks.map(c => c.content).join("\n---\n");
const prompt = `Use the following context to answer.\n${context}\n\nQuestion: ${callerMessage}`;
// → send `prompt` to your own LLM, return the reply to Voicebip
```

## How retrieval works (and why it sometimes returns nothing)

1. The query (or caller message) is embedded as a vector.
2. Cosine-distance search over the KB's `ready` chunks (HNSW index) finds the closest.
3. Top `top_k` returned best-first, **after dropping anything below the relevance threshold**.
4. Hosted agents: chunks are prepended to the system prompt. BYOM: you assemble the prompt.

For hosted agents, retrieval is **fail-soft** — if it errors or exceeds a 1-second budget, the agent still answers, just without KB context for that turn. The **relevance gate** is deliberate: injecting weakly-related passages causes *more* hallucination, so "no good match → no context" is the correct behaviour, not a bug.

Results are cached per `(workspace, KB, query)` and invalidated whenever you add, delete, or change a document — updates appear immediately.

## Manage KBs and documents

```bash
# list KBs (newest first)
curl "https://api.voicebip.com/v1/knowledge-bases?limit=50&offset=0" -H "Authorization: Bearer pk_xxx"
# rename
curl -X PATCH https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3 \
  -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" -d '{"name":"Support FAQ v2"}'
# delete one document (removes its chunks)
curl -X DELETE https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3/documents/doc_4kq… -H "Authorization: Bearer pk_xxx"
# delete the whole KB (detaches from any agents referencing it)
curl -X DELETE https://api.voicebip.com/v1/knowledge-bases/kb_8sd2k1fapvq3 -H "Authorization: Bearer pk_xxx"
```

## Limits

| Limit                     | Value               |
| ------------------------- | ------------------- |
| Max document size         | 50 MiB              |
| Formats                   | PDF, DOCX, TXT, URL |
| `top_k`                   | 1–10 (default 5)    |
| Max query length          | 4096 chars          |
| Upload URL lifetime       | \~10 min            |
| Retrieval budget (hosted) | \~1 s, fail-soft    |

## Dashboard & MCP

* **Dashboard** → **Knowledge** section: create, drag-drop docs, watch ingestion live.
* **MCP** → the [MCP server](/integrations/mcp/overview) exposes seven KB tools (`create_knowledge_base`, `list_knowledge_bases`, `upload_knowledge_document`, `complete_knowledge_document`, `get_document_status`, `query_knowledge_base`, `attach_knowledge_base`).

## Next steps

* Ground a live phone agent in this KB → [Inbound support + KB](/use-cases/inbound-support-kb).
* Do your own retrieval in a custom model → [BYOM](/use-cases/byom-custom-llm).