Skip to Content
API ReferenceKnowledge

Knowledge

The Knowledge endpoints manage the documents your agents draw on, plus the folders and tags that organize them. There are two groups:

  • Documents — upload (asynchronous), list, search, fetch, track processing, and delete.
  • Organization — folder CRUD, tag CRUD, and document organization (move to a folder, add or remove tags).

All endpoints are under /knowledge and require a knowledge:read scope for reads or a knowledge:write scope for writes. Every response uses the deny-by-default shapes documented here — storage internals (S3 keys, file hashes, MIME types), chunking and embedding internals, and cost figures are never returned.

Documents

The async upload model

Uploading a document does not block on processing. POST /knowledge/documents returns 201 with {document_id, status} the moment the file is accepted, then the document moves through an asynchronous lifecycle:

uploaded → validating → stored → processing → ready

(or failed on error). To follow it, either poll GET /knowledge/documents/{document_id}/status or subscribe to the SSE stream GET /knowledge/documents/{document_id}/status/stream. Only once a document is ready is it searchable and usable by an agent.


POST /knowledge/documents

Upload a file to the knowledge base. Asynchronous — returns 201 immediately with the new document id and its initial (non-terminal) status. If the file matches an existing document, the endpoint returns 409 with a structured duplicate body (see below), not the error envelope.

Scope: knowledge:write · Success: 201

This endpoint takes multipart/form-data, not JSON.

ParameterInTypeRequiredDescription
fileformfileYesThe document file to upload.
titleformstringNoA display title. Defaults to the filename.
descriptionformstringNoA free-text description.
tagsformstringNoComma-separated tag ids to apply on upload.
folder_idformstringNoThe folder to file the document into.
visibilityformstringNoAccess visibility. Defaults to private.
Idempotency-KeyheaderstringNoReplay-safe retry key (see Conventions).
curl -X POST https://cuneiform.chat/api/developer/v1/knowledge/documents \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -F "file=@handbook.pdf" \ -F "title=Employee Handbook" \ -F "folder_id=fold_abc123" \ -F "tags=tag_hr,tag_policy"
{ "document_id": "doc_9f2a7b", "status": "uploaded" }

Duplicate detected (409). When the uploaded file matches an existing document, the response is a structured body — not the error envelope — carrying an upload_session_id you pass to confirm-duplicate to proceed anyway:

{ "upload_session_id": "ups_abc123", "duplicate_of": ["doc_existing456"] }

Errors: 400 invalid_upload (bad file), 401, 403, 429, 500.


POST /knowledge/documents/confirm-duplicate

Resume an upload that was flagged as a duplicate, identified by the upload_session_id from the 409 body. Like upload, this is asynchronous and returns 201 with {document_id, status}.

Scope: knowledge:write · Success: 201

This endpoint takes multipart/form-data.

ParameterInTypeRequiredDescription
upload_session_idformstringYesThe id from the 409 duplicate body.
titleformstringNoA display title.
descriptionformstringNoA free-text description.
tagsformstringNoComma-separated tag ids.
folder_idformstringNoThe folder to file into.
visibilityformstringNoDefaults to private.
Idempotency-KeyheaderstringNoReplay-safe retry key.
curl -X POST https://cuneiform.chat/api/developer/v1/knowledge/documents/confirm-duplicate \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -F "upload_session_id=ups_abc123" \ -F "folder_id=fold_abc123"
{ "document_id": "doc_9f2a7b", "status": "uploaded" }

Errors: 400, 401, 403, 404 (unknown session), 429, 500.


GET /knowledge/documents

List documents, cursor-paginated. Optional filters narrow by folder, tag, or processing status.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
limitqueryintegerNoPage size, 1–100. Defaults to 20.
cursorquerystringNoThe next_cursor from the previous page.
folder_idquerystringNoRestrict to a folder.
tagquerystringNoRestrict to a tag id.
statusquerystringNoRestrict to a processing status.
curl "https://cuneiform.chat/api/developer/v1/knowledge/documents?limit=20&status=ready" \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "data": [ { "id": "doc_9f2a7b", "filename": "handbook.pdf", "title": "Employee Handbook", "description": null, "file_format": "pdf", "file_size_bytes": 184320, "status": "ready", "folder_id": "fold_abc123", "tags": ["tag_hr", "tag_policy"], "is_duplicate": false, "duplicate_of": [], "total_chunks": 42, "created_at": "2026-06-07T09:12:00Z", "updated_at": "2026-06-07T09:13:20Z" } ], "has_more": false, "next_cursor": null }

Errors: 400 invalid_cursor, 401, 403, 429, 500.


GET /knowledge/documents/search

Search documents by a query string. Returns a cursor-paginated page of Documents ranked by relevance, with the same optional filters as the list endpoint.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
qquerystringNoThe search query string.
limitqueryintegerNoPage size, 1–100. Defaults to 20.
cursorquerystringNoThe next_cursor from the previous page.
folder_idquerystringNoRestrict to a folder.
tagquerystringNoRestrict to a tag id.
statusquerystringNoRestrict to a processing status.
curl "https://cuneiform.chat/api/developer/v1/knowledge/documents/search?q=parental%20leave" \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "data": [ { "id": "doc_9f2a7b", "filename": "handbook.pdf", "title": "Employee Handbook", "description": null, "file_format": "pdf", "file_size_bytes": 184320, "status": "ready", "folder_id": "fold_abc123", "tags": ["tag_hr", "tag_policy"], "is_duplicate": false, "duplicate_of": [], "total_chunks": 42, "created_at": "2026-06-07T09:12:00Z", "updated_at": "2026-06-07T09:13:20Z" } ], "has_more": false, "next_cursor": null }

Errors: 400, 401, 403, 429, 500.


GET /knowledge/documents/{document_id}

Fetch a single document by id.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
curl https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "doc_9f2a7b", "filename": "handbook.pdf", "title": "Employee Handbook", "description": null, "file_format": "pdf", "file_size_bytes": 184320, "status": "ready", "folder_id": "fold_abc123", "tags": ["tag_hr", "tag_policy"], "is_duplicate": false, "duplicate_of": [], "total_chunks": 42, "created_at": "2026-06-07T09:12:00Z", "updated_at": "2026-06-07T09:13:20Z" }

Errors: 401, 403, 404 document_not_found, 429, 500.


GET /knowledge/documents/{document_id}/status

Poll a document’s asynchronous processing status. Use this to know when an upload reaches ready.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
curl https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b/status \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "document_id": "doc_9f2a7b", "status": "processing", "progress": 60, "error_message": null }

Errors: 401, 403, 404, 429, 500.


GET /knowledge/documents/{document_id}/status/stream

Subscribe to a Server-Sent Events stream of a document’s processing status. Each event’s data: payload is a status object (the same shape as the poll endpoint). The stream emits the current status immediately, then one event per update, and closes when the status reaches a terminal state (ready or failed).

Scope: knowledge:read · Success: 200 (text/event-stream)

A document id outside your organization returns a 404 error envelope — not an empty stream.

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
curl -N https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b/status/stream \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
data: {"document_id": "doc_9f2a7b", "status": "processing", "progress": 40, "error_message": null} data: {"document_id": "doc_9f2a7b", "status": "processing", "progress": 80, "error_message": null} data: {"document_id": "doc_9f2a7b", "status": "ready", "progress": 100, "error_message": null}

Errors: 401, 403, 404, 429, 500.


DELETE /knowledge/documents/{document_id}

Delete a document.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
curl -X DELETE https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "doc_9f2a7b", "deleted": true }

Errors: 401, 403, 404, 429, 500.

Organization

POST /knowledge/folders

Create a folder.

Scope: knowledge:write · Success: 201

ParameterInTypeRequiredDescription
namebodystringYesFolder name (1–100 chars).
descriptionbodystringNoA description (≤500 chars).
colorbodystringNoA #RRGGBB hex color. Defaults to #667eea.
curl -X POST https://cuneiform.chat/api/developer/v1/knowledge/folders \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "name": "HR Policies", "color": "#667eea" }'
{ "id": "fold_abc123", "name": "HR Policies", "description": null, "color": "#667eea", "document_count": 0, "created_at": "2026-06-07T09:00:00Z", "updated_at": "2026-06-07T09:00:00Z" }

Errors: 400 folder_name_exists, 401, 403, 429, 500.


GET /knowledge/folders

List folders, cursor-paginated.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
limitqueryintegerNoPage size, 1–100. Defaults to 20.
cursorquerystringNoThe next_cursor from the previous page.
curl "https://cuneiform.chat/api/developer/v1/knowledge/folders?limit=20" \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "data": [ { "id": "fold_abc123", "name": "HR Policies", "description": null, "color": "#667eea", "document_count": 12, "created_at": "2026-06-07T09:00:00Z", "updated_at": "2026-06-07T09:13:20Z" } ], "has_more": false, "next_cursor": null }

Errors: 400, 401, 403, 429, 500.


GET /knowledge/folders/{folder_id}

Fetch a folder by id.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
folder_idpathstringYesThe folder id.
curl https://cuneiform.chat/api/developer/v1/knowledge/folders/fold_abc123 \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "fold_abc123", "name": "HR Policies", "description": null, "color": "#667eea", "document_count": 12, "created_at": "2026-06-07T09:00:00Z", "updated_at": "2026-06-07T09:13:20Z" }

Errors: 401, 403, 404, 429, 500.


PATCH /knowledge/folders/{folder_id}

Update a folder. All body fields are optional; omitted fields are left unchanged.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
folder_idpathstringYesThe folder id.
namebodystringNoNew name (1–100 chars).
descriptionbodystringNoNew description (≤500 chars).
colorbodystringNoNew #RRGGBB hex color.
curl -X PATCH https://cuneiform.chat/api/developer/v1/knowledge/folders/fold_abc123 \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "name": "HR & Compliance" }'
{ "id": "fold_abc123", "name": "HR & Compliance", "description": null, "color": "#667eea", "document_count": 12, "created_at": "2026-06-07T09:00:00Z", "updated_at": "2026-06-07T10:01:00Z" }

Errors: 400 folder_name_exists, 401, 403, 404, 429, 500.


DELETE /knowledge/folders/{folder_id}

Delete an empty folder. A folder that still contains documents returns 400 folder_not_empty — move or delete its documents first.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
folder_idpathstringYesThe folder id.
curl -X DELETE https://cuneiform.chat/api/developer/v1/knowledge/folders/fold_abc123 \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "fold_abc123", "deleted": true }

Errors: 400 folder_not_empty, 401, 403, 404, 429, 500.


POST /knowledge/tags

Create a tag.

Scope: knowledge:write · Success: 201

ParameterInTypeRequiredDescription
namebodystringYesTag name (1–50 chars).
colorbodystringYesA #RRGGBB hex color.
curl -X POST https://cuneiform.chat/api/developer/v1/knowledge/tags \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "name": "policy", "color": "#10b981" }'
{ "id": "tag_policy", "name": "policy", "color": "#10b981", "document_count": 0, "created_at": "2026-06-07T09:00:00Z" }

Errors: 400 tag_name_exists, 401, 403, 429, 500.


GET /knowledge/tags

List tags, cursor-paginated.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
limitqueryintegerNoPage size, 1–100. Defaults to 20.
cursorquerystringNoThe next_cursor from the previous page.
curl "https://cuneiform.chat/api/developer/v1/knowledge/tags?limit=20" \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "data": [ { "id": "tag_policy", "name": "policy", "color": "#10b981", "document_count": 7, "created_at": "2026-06-07T09:00:00Z" } ], "has_more": false, "next_cursor": null }

Errors: 400, 401, 403, 429, 500.


GET /knowledge/tags/{tag_id}

Fetch a tag by id.

Scope: knowledge:read · Success: 200

ParameterInTypeRequiredDescription
tag_idpathstringYesThe tag id.
curl https://cuneiform.chat/api/developer/v1/knowledge/tags/tag_policy \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "tag_policy", "name": "policy", "color": "#10b981", "document_count": 7, "created_at": "2026-06-07T09:00:00Z" }

Errors: 401, 403, 404, 429, 500.


PATCH /knowledge/tags/{tag_id}

Update a tag. All body fields are optional.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
tag_idpathstringYesThe tag id.
namebodystringNoNew name (1–50 chars).
colorbodystringNoNew #RRGGBB hex color.
curl -X PATCH https://cuneiform.chat/api/developer/v1/knowledge/tags/tag_policy \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "color": "#3b82f6" }'
{ "id": "tag_policy", "name": "policy", "color": "#3b82f6", "document_count": 7, "created_at": "2026-06-07T09:00:00Z" }

Errors: 400 tag_name_exists, 401, 403, 404, 429, 500.


DELETE /knowledge/tags/{tag_id}

Delete a tag. This also removes the tag from every document it was applied to.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
tag_idpathstringYesThe tag id.
curl -X DELETE https://cuneiform.chat/api/developer/v1/knowledge/tags/tag_policy \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "id": "tag_policy", "deleted": true }

Errors: 401, 403, 404, 429, 500.


PUT /knowledge/documents/{document_id}/folder

Move a document into a folder, or unfile it by passing folder_id: null.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
folder_idbodystring | nullNoThe target folder id, or null to unfile.
curl -X PUT https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b/folder \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "folder_id": "fold_abc123" }'
{ "document_id": "doc_9f2a7b", "folder_id": "fold_abc123" }

Errors: 400, 401, 403, 404, 429, 500.


POST /knowledge/documents/{document_id}/tags

Add one or more tags to a document. The response is the document’s full tag set after the addition.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
tag_idsbodyarray of stringYesThe tag ids to add (1–20).
curl -X POST https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b/tags \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "tag_ids": ["tag_hr", "tag_policy"] }'
{ "document_id": "doc_9f2a7b", "tag_ids": ["tag_hr", "tag_policy"] }

Errors: 400, 401, 403, 404, 429, 500.


DELETE /knowledge/documents/{document_id}/tags/{tag_id}

Remove a single tag from a document. The response is the document’s remaining tag set.

Scope: knowledge:write · Success: 200

ParameterInTypeRequiredDescription
document_idpathstringYesThe document id.
tag_idpathstringYesThe tag id to remove.
curl -X DELETE https://cuneiform.chat/api/developer/v1/knowledge/documents/doc_9f2a7b/tags/tag_policy \ -H "Authorization: Bearer cuk_live_xxxxxxxxxxxxxxxx"
{ "document_id": "doc_9f2a7b", "tag_ids": ["tag_hr"] }

Errors: 401, 403, 404, 429, 500.

Last updated on