Dynamiq
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 (pendingprocessingprocessed, 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}/traceGet the item's ingestion trace
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