Knowledge (RAG) API
The knowledge data plane ingests documents into a knowledge base (a Qdrant collection) and searches it. Create the knowledge base itself in the panel under Knowledge; these endpoints populate and query it by id. They need only a valid key — no scope.
See Knowledge bases (RAG) for concepts.
Every endpoint returns 503 vector_store_unavailable when Qdrant:Url is not configured, and 404 knowledge_base_not_found for an unknown id.
#Ingest a document
POST /v1/knowledge/{id}/documents
{ "title": "Returns policy", "source": "handbook", "content": "Items may be returned within 14 days…" }
title and content are required. The content is chunked, embedded (via the model router, with the knowledge base's embedding model) and upserted into the vector store. The response is { "id": "…", "status": "indexed", "chunks": 7 }.
#Upload a file
POST /v1/knowledge/{id}/files — multipart upload of one file, with an optional title form field (defaults to the file name). Supported types: .md, .markdown, .mdx, .txt, .csv, .tsv, .json, .log, .pdf, .docx, .xlsx, .pptx (max 25 MB). Text is extracted server-side by the same BCL-only extractors file attachments use, so anything one endpoint reads the other reads too; Markdown has its own extractor that strips syntax and keeps the prose — see knowledge bases. Unlike an attachment, ingest keeps the whole file: nothing is truncated, because this path chunks and embeds.
curl -X POST http://localhost:5300/v1/knowledge/KB_ID/files \
-H "Authorization: Bearer $RELAY_API_KEY" \
-F "file=@returns-policy.pdf" -F "title=Returns policy (2026)"
The response carries chunks, the number of embedded chunks the document produced, and characters, how much text was extracted. A file type outside the list is 400 unsupported_file_type; a file with no text layer (a scanned PDF) is 422 no_text_extracted.
To import a batch, call this once per file, or use the panel's multi-file picker, which does exactly that and reports each file's result.
#Ingest a URL
POST /v1/knowledge/{id}/url
{ "url": "https://intranet.example.com/policies/returns", "title": "Returns policy" }
Relay fetches the page (30-second timeout), strips HTML to text, and ingests it. title is optional and defaults to the host and path. A page that cannot be fetched is 422 fetch_failed; one with no text is 422 no_text_extracted.
#Search
POST /v1/knowledge/{id}/search
{ "query": "how long do I have to return something?", "topK": 4, "hybrid": true, "filter": { "title": "Returns policy" } }
| Field | Meaning |
|---|---|
query | Required. |
topK | Results to return. Default 5, clamped 1–50. |
hybrid | Default true: dense vector candidates fused with a BM25 lexical score, then MMR re-ranking for diversity. false is pure vector search. |
filter | Optional payload-equality filter, e.g. { "doc_id": "…" } or { "title": "…" }, applied inside the vector search. |
{ "object": "list", "data": [
{ "text": "Items may be returned within 14 days…", "score": 0.82, "documentId": "3c9e…", "title": "Returns policy" }
] }
#Using it from an agent
Attach a knowledge base to an agent and Relay retrieves relevant chunks automatically, folding them into the system prompt with [S#] citation tags — no manual search call needed. In a voice session the same retrieval is exposed to the model as a tool the gateway executes.