Knowledge Bases

Knowledge Base API

The full HTTP contract of a Knowledge Base's hostname — multipart ingestion, item reprocess and delete, and the documents search endpoint.

Every Knowledge Base serves its own hostname (shown on the Knowledge Base page; the Ingestion and Retrieval tabs generate ready-made snippets against it). That hostname is the data plane: it ingests files and answers searches. Item and source management — listing, traces, downloads, sync control — lives on the management API at https://api.getdynamiq.ai and is covered in Data Sources and the API reference.

Authentication

All requests carry an Access Key as a Bearer token:

Authorization: Bearer $DYNAMIQ_ACCESS_KEY

A project-scoped key must belong to the Knowledge Base's project.

Upload files

POST https://<your-kb-hostname> with multipart form data. Each file becomes a Knowledge Base item, queued (pending) and processed asynchronously by the ingestion workflow.

filesfilerequired
One form part per file. Repeat the field to upload several files in one request.
inputstring
A JSON object as a string. Its metadata array attaches one metadata object per file — the array length must match the number of files, or the request fails with 400.
idsstring
A JSON array of existing item UUIDs, same length as files. Each file replaces the item at the same position: the old file and its vectors are removed and the item is re-ingested.

The total request size is limited to 128 MB.

curl -X POST "https://<your-kb-hostname>" \
  -H "Authorization: Bearer $DYNAMIQ_ACCESS_KEY" \
  -F "files=@handbook.pdf" \
  -F "files=@org-chart.png" \
  -F 'input={"metadata": [{"department": "hr"}, {"department": "hr"}]}'
import json
import os

import requests

URL = "https://<your-kb-hostname>"
HEADERS = {"Authorization": f"Bearer {os.environ['DYNAMIQ_ACCESS_KEY']}"}

file_paths = ["handbook.pdf", "org-chart.png"]
files = [("files", open(path, "rb")) for path in file_paths]
data = {"input": json.dumps({"metadata": [{"department": "hr"}, {"department": "hr"}]})}

response = requests.post(URL, data=data, files=files, headers=HEADERS)

for _, file in files:
    file.close()

print(response.json())
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("files", await openAsBlob("handbook.pdf"), "handbook.pdf");
form.append("files", await openAsBlob("org-chart.png"), "org-chart.png");
form.append(
  "input",
  JSON.stringify({ metadata: [{ department: "hr" }, { department: "hr" }] }),
);

const response = await fetch("https://<your-kb-hostname>", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DYNAMIQ_ACCESS_KEY}` },
  body: form,
});

console.log(await response.json());

The response returns one record per file:

{
  "data": [
    {
      "id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21",
      "name": "handbook.pdf",
      "status": "pending",
      "uploaded_at": "2026-06-10T09:15:42.51437Z",
      "metadata": {
        "department": "hr",
        "file_id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21",
        "dynamiq_item_id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21"
      }
    }
  ]
}

Two fields are always merged into your metadata: dynamiq_item_id and its legacy alias file_id, both set to the item's ID — they tag every chunk so the item's vectors can be found, replaced, and deleted later. Poll the item's status (pending → processing → processed, or failed) via the items endpoints.

Accepted file types

Files are validated by detected MIME type (not extension). Allowed: PDF; Word, Excel, and PowerPoint (both legacy and OpenXML formats); text formats (plain text, HTML, XML, CSV, TSV, Markdown); JSON; RTF; EPUB; and images (JPEG, PNG, GIF, WebP, SVG, TIFF, BMP). Anything else is rejected with 400 and a message naming the file and its detected MIME type.

Reprocess an item

POST https://<your-kb-hostname>?action=reprocess re-runs the current ingestion workflow on an item's stored file — use it after changing the pipeline or to retry a failure:

curl -X POST "https://<your-kb-hostname>?action=reprocess" \
  -H "Authorization: Bearer $DYNAMIQ_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"knowledgebase_file_id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21"}'

The response is the item record with status reset to pending. To reprocess in bulk by status (for example all failed items), use the management API's POST /v1/knowledgebases/{knowledgebase_id}/items/reprocess with {"statuses": ["failed"]}.

Delete an item

DELETE https://<your-kb-hostname>/v1/items/{item_id} removes the item's vectors from the vector store, its file from storage, and its record:

curl -X DELETE "https://<your-kb-hostname>/v1/items/0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21" \
  -H "Authorization: Bearer $DYNAMIQ_ACCESS_KEY"

Items that came from a synced source can't be deleted this way (400) — manage them through the source instead, as described in Data Sources.

Search documents

POST https://<your-kb-hostname>/v1/documents/search embeds the query with the Knowledge Base's ingestion embedder and returns the best-matching chunks.

querystringrequired
The search text. Embedded server-side with the same embedder used at ingestion.
limitinteger
Maximum number of chunks to return. Between 1 and 100.
curl -X POST "https://<your-kb-hostname>/v1/documents/search" \
  -H "Authorization: Bearer $DYNAMIQ_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "Onboarding procedures documentation", "limit": 10}'
import os

import requests

URL = "https://<your-kb-hostname>/v1/documents/search"
HEADERS = {
    "Authorization": f"Bearer {os.environ['DYNAMIQ_ACCESS_KEY']}",
    "Content-Type": "application/json",
}

payload = {"query": "Onboarding procedures documentation", "limit": 10}

response = requests.post(URL, json=payload, headers=HEADERS)

print(response.json())
const response = await fetch("https://<your-kb-hostname>/v1/documents/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DYNAMIQ_ACCESS_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: "Onboarding procedures documentation", limit: 10 }),
});

console.log(await response.json());

Results arrive under data, each chunk with its content, metadata, and similarity score:

{
  "data": [
    {
      "id": "5b1f6c3a-9f4e-4a39-8a37-1d2e0f9a6b21",
      "content": "New hires complete onboarding within the first two weeks...",
      "metadata": {
        "file_id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21",
        "dynamiq_item_id": "0d9b7a52-3c1e-4f8b-9a2d-7e6f5c4b3a21",
        "department": "hr"
      },
      "score": 0.79
    }
  ]
}

How to interpret chunks and scores — and how to test filters and thresholds, which apply on retriever nodes rather than this endpoint — is covered in Search & Test.

Management API summary

The control plane at https://api.getdynamiq.ai rounds out the lifecycle. The most used endpoints:

MethodPathPurpose
POST/v1/knowledgebases/{knowledgebase_id}/uploadUpload files (same multipart shape as the hostname upload)
GET/v1/knowledgebases/{knowledgebase_id}/itemsList items, filterable by status and source_id
GET/v1/knowledgebase-items/{knowledgebase_item_id}Get one item
GET/v1/knowledgebase-items/{knowledgebase_item_id}/downloadDownload the original file
PUT/v1/knowledgebase-items/{knowledgebase_item_id}/uploadReplace the item's file (multipart file field) and re-ingest
DELETE/v1/knowledgebase-items/{knowledgebase_item_id}Delete an item and its vectors
POST/v1/knowledgebases/{knowledgebase_id}/items/bulk/deleteDelete many items ({"ids": [...]})

Source management endpoints (create, sync, pause, resume, sync history) are listed in Data Sources.

Next steps

On this page