API reference · Voice Intelligence
Knowledge Bases
A knowledge base is a set of documents an AI agent searches while it talks: hours, prices, service areas, policies. Agents answer from it instead of guessing.
Knowledge bases use the agent scopes.
| Route | Scope |
|---|---|
GET /document/public/knowledge-bases |
agents:read |
POST /document/public/knowledge-bases |
agents:write |
GET /document/public/knowledge-bases/{knowledge_base_id} |
agents:read |
POST /document/public/knowledge-bases/{knowledge_base_id} |
agents:write |
DELETE /document/public/knowledge-bases/{knowledge_base_id} |
agents:write |
GET /document/public/knowledge-bases/{knowledge_base_id}/documents |
agents:read |
POST /document/public/knowledge-bases/{knowledge_base_id}/documents |
agents:write |
POST /document/public/knowledge-bases/{knowledge_base_id}/documents/{knowledge_document_id}/uploaded |
agents:write |
POST /document/public/knowledge-bases/{knowledge_base_id}/documents/{knowledge_document_id}/upload-url |
agents:write |
DELETE /document/public/knowledge-bases/{knowledge_base_id}/documents/{knowledge_document_id} |
agents:write |
POST /document/public/knowledge-bases/{knowledge_base_id}/query |
agents:read |
An id that belongs to another account answers 404, the same as one that does
not exist.
Create a knowledge base
curl -X POST https://api-v2.dropcowboy.com/document/public/knowledge-bases \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer FAQ",
"description": "Hours, pricing and service area for callers.",
"ai_audience": "public"
}'
{
"data": {
"knowledge_base_id": "9d3f6a2c-4e8b-4b1d-a7c5-2f6e9b3d8a14",
"name": "Customer FAQ",
"description": "Hours, pricing and service area for callers.",
"ai_audience": "public",
"status": "active",
"stats": { "document_count": 0, "ready_count": 0, "failed_count": 0, "chunk_count": 0 },
"created_at": 1774041600000,
"updated_at": 1774041600000
},
"meta": { "request_id": "8a2f6c1e-4d9b-4e7a-b3c5-6f1d8e2a9c47" }
}
| Field | Notes |
|---|---|
name |
Required, up to 200 characters. |
description |
Up to 2000 characters. |
ai_audience |
public for content that may be read to customers. internal for agents that help your staff. |
Update with POST .../{knowledge_base_id}, sending only the fields to change.
You can also set status to archived or back to active. Timestamps are
epoch milliseconds.
Add documents
One route, three ways. The fields you send pick the method.
Inline markdown
Best for FAQs you already have as text. Up to 1 MB.
{
"title": "Hours and location",
"markdown": "# Hours\n\nMonday to Friday, 8am to 6pm. Saturday, 9am to 1pm. Closed Sunday.\n\n# Location\n\n100 Example Street, Springfield."
}
From a URL
{
"source_url": "https://www.example.com/files/price-list.pdf",
"title": "Price list"
}
DropCowboy downloads the file. It must be on a public http(s) address and no
larger than 25 MB. If the server labels the file with a supported type, that
type wins; otherwise send mime_type. URL problems are listed under
Errors.
Upload a file
Three steps, for files up to 25 MB.
1. Ask for an upload ticket:
{
"title": "Price list",
"filename": "price-list.pdf",
"mime_type": "application/pdf",
"byte_size": 184320
}
{
"data": {
"knowledge_document_id": "5b8e1c4f-7a2d-4f9e-b3c6-8d1a5e2f7b40",
"knowledge_document": { "ingest_status": "pending", "upload_confirmed": false },
"upload": {
"method": "PUT",
"url": "https://uploads.example.com/knowledge/price-list.pdf?signature=example-signature",
"headers": { "Content-Type": "application/pdf" },
"max_bytes": 26214400
}
}
}
2. PUT the file to upload.url with exactly the headers in
upload.headers. The URL is signed for that Content-Type and rejects any
other. It expires after 48 hours; if it has, get a new one (see
Get a new upload URL).
curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/pdf" --data-binary @price-list.pdf
3. Confirm:
curl -X POST \
"https://api-v2.dropcowboy.com/document/public/knowledge-bases/$KB_ID/documents/$DOC_ID/uploaded" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
A stored file over 25 MB answers 413, and a file identical to one already
in the knowledge base answers 409 (duplicate-knowledge-document). Either
one marks the document failed, with ingest_error set to
Uploaded file exceeds the 26214400 byte limit or
This document is already in this knowledge base. To recover, PUT different
bytes to upload.url (or a new upload URL) and
confirm again; a successful confirm clears ingest_error. Otherwise delete the
document with the document DELETE route and start over.
Confirming twice answers 409 (already-confirmed), and confirming before
the file was uploaded answers 400. Neither changes the document, which
stays pending until a confirm succeeds.
Get a new upload URL
If the upload URL expired before you used it, or a confirm was refused and you want to send different bytes, ask for a new one:
curl -X POST \
"https://api-v2.dropcowboy.com/document/public/knowledge-bases/$KB_ID/documents/$DOC_ID/upload-url" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
The response is 200 with the same shape as the upload ticket in step 1. The
new URL writes the same file with the same Content-Type, so PUT and
confirm exactly as before. A document that was marked failed by a refused
confirm goes back to pending, with ingest_error cleared.
Each call signs another URL and changes nothing else, so it is safe to retry.
Earlier URLs keep working until they expire. It only works before a confirm
succeeds: once the upload is confirmed, the route answers 409
(already-confirmed), whether the document is still processing, ready or
failed during processing. To replace a confirmed document, delete it and add
it again. Markdown and URL documents are confirmed when they are created, so
they answer 409 too.
Supported types
The file extension must match mime_type.
| Type | Extensions |
|---|---|
.pdf |
|
| Word | .doc, .docx |
| Excel | .xls, .xlsx |
| PowerPoint | .ppt, .pptx |
| Rich text, OpenDocument | .rtf, .odt |
| Web page | .html |
| Text, markdown, CSV, JSON | .txt, .log, .md, .csv, .json |
Anything else answers 415.
Adding a file identical to one already in the knowledge base answers 409,
with the existing document's id in details.existing_knowledge_document_id.
Wait for processing
Every document is processed in the background into searchable passages. Poll
the document list and check ingest_status:
ingest_status |
Meaning |
|---|---|
pending |
Queued, or waiting for the upload to be confirmed. |
processing |
Being converted. |
ready |
Searchable. chunk_count shows how many passages it produced. |
failed |
Could not be processed. ingest_error says why. |
The knowledge base's stats roll up the same counts. Only ready documents
are searched.
curl "https://api-v2.dropcowboy.com/document/public/knowledge-bases/$KB_ID/documents?limit=100" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
Lists page with limit (default 25, maximum 100) and offset. The totals are
in meta.total.
Test it
Before attaching a knowledge base, ask it the questions callers will ask:
curl -X POST "https://api-v2.dropcowboy.com/document/public/knowledge-bases/$KB_ID/query" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{ "query": "What are your hours on Saturday?" }'
{
"data": {
"query": "What are your hours on Saturday?",
"results": [
{
"chunk_id": "7f4c2a9e-3b1d-4e6a-8c5f-9d2b7e1a4c36",
"knowledge_base_id": "9d3f6a2c-4e8b-4b1d-a7c5-2f6e9b3d8a14",
"knowledge_document_id": "2c7a9e4b-1d6f-4a3e-8b5c-7f2d9a6e1c83",
"chunk_index": 0,
"text": "Monday to Friday, 8am to 6pm. Saturday, 9am to 1pm. Closed Sunday.",
"score": 0.87,
"heading": "Hours",
"section_path": "Hours",
"page": null
}
]
}
}
These are the passages an agent would retrieve, best first. query is limited
to 1000 characters. If the right passage is missing, improve the document
before attaching it.
Attach to an agent
Set think.knowledge on the agent, then publish:
{
"think": {
"prompt_spec": { "role": "Receptionist for Example Dental" },
"knowledge": {
"mode": "selected",
"knowledge_base_ids": ["9d3f6a2c-4e8b-4b1d-a7c5-2f6e9b3d8a14"],
"audience": "public"
}
}
}
| Key | Notes |
|---|---|
mode |
selected searches only knowledge_base_ids (the default when ids are given). all searches every knowledge base on the account with the matching audience. |
knowledge_base_ids |
The knowledge bases to search. |
audience |
public (default) or internal. Must match the knowledge bases' ai_audience, or nothing is found. |
Updating think replaces the whole object, so send the agent's existing
think with knowledge added. AI agents has a complete example.
Publishing checks selected knowledge bases. It fails with 400 if their
content reads like instructions for your staff ("click Settings, then...")
rather than answers for callers, or tells callers to check an app for your
hours without stating them. Write documents the way you want the agent to
speak.
Delete
DELETE .../documents/{knowledge_document_id}removes one document.DELETE /document/public/knowledge-bases/{knowledge_base_id}removes the knowledge base. Take its id out of any agent'sthink.knowledgetoo.
Errors
Knowledge routes use the standard error body (see errors and limits):
| Status | type ends with |
Cause |
|---|---|---|
400 |
missing-parameters, invalid-parameters, invalid-filename, invalid-request |
A field is missing or out of range. |
400 |
url-required, url-invalid, url-protocol-blocked, url-credentials |
source_url is empty, malformed, not http(s), or has a user name or password in it. |
400 |
url-private-host, url-unresolvable |
The host is a private address, or does not resolve. |
400 |
empty-file |
The file or download was empty. |
403 |
insufficient-scope |
The credentials lack the scope in the table above. |
403 |
forbidden |
A signed-in user's role does not allow it. See below. |
404 |
not-found |
Unknown knowledge base or document. |
409 |
duplicate-knowledge-document, already-confirmed |
See above. |
413 |
payload-too-large, url-too-large |
Over 1 MB of markdown or 25 MB of file. |
415 |
unsupported-media-type |
Type not supported, or extension mismatch. |
502 |
url-fetch-failed, url-too-many-redirects |
The download failed. |
504 |
url-timeout |
The download took too long. |
A token issued for a signed-in user whose role cannot use or manage AI agents
gets a 403 with type ending forbidden. detail is
You do not have permission to use Knowledge Bases. on reads and
You do not have permission to manage Knowledge Bases. on changes:
{
"type": "https://api-v2.dropcowboy.com/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "You do not have permission to manage Knowledge Bases.",
"instance": "/document/public/knowledge-bases",
"request_id": "3c5e7a9b-1d2f-4a6c-8e0b-5f7d9a1c3e62"
}
If the role cannot be looked up, the answer is 500 (server-error). API
keys are never limited by role.