Relay docs

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.

POST /v1/knowledge/{id}/search

{ "query": "how long do I have to return something?", "topK": 4, "hybrid": true, "filter": { "title": "Returns policy" } }
FieldMeaning
queryRequired.
topKResults to return. Default 5, clamped 1–50.
hybridDefault true: dense vector candidates fused with a BM25 lexical score, then MMR re-ranking for diversity. false is pure vector search.
filterOptional 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.