Skip to main content

Documents

A document is one unit of knowledge-base content: an uploaded file or a crawled page. The documents endpoints let you inspect what your knowledge base holds, check whether each document is ready to be cited, and remove content.

All three operations require the ingest scope and see only the documents of the account the key belongs to.

OperationPath
List documentsGET /v1/documents
Retrieve a documentGET /v1/documents/{documentId}
Delete a documentDELETE /v1/documents/{documentId}

The document object

{
"id": "17136f01-972d-4956-868e-8159833072e4",
"object": "document",
"namespace": "general",
"filename": "traffic-division-faq.pdf",
"source_type": "upload",
"source_url": null,
"status": "ready",
"chunk_count": 18,
"error": null,
"created_at": "2026-08-21T14:03:11.214000Z",
"updated_at": "2026-08-21T14:03:42.908000Z"
}
FieldTypeDescription
idstringUUID of the document. Returned as document_ids[] by the upload call and as document_id in job errors and citations.
objectstringAlways document.
namespacestringThe knowledge-base namespace the document belongs to.
filenamestringFor uploads, the sanitized filename (Filenames). For crawled pages, the final page URL.
source_typestringupload or crawl.
source_urlstring or nullThe final page URL for crawled pages; null for uploads.
statusstringProcessing state; see Status values.
chunk_countintegerNumber of indexed chunks. Greater than 0 only when status is ready; otherwise 0.
errorstring or nullThe sanitized failure reason when status is failed (the same text as the job's errors[] entry); null otherwise.
created_atstringRFC 3339 UTC timestamp (Z designator) of when the document was created; millisecond precision rendered with six fractional digits (Timestamps). Never changes, and every document from one upload request shares the same value.
updated_atstringRFC 3339 UTC timestamp, same form, of the last status transition.

Status values

StatusMeaning
processingCreated and waiting for, or undergoing, text extraction and indexing. This also covers the time between automatic retries after a transient failure. chunk_count is 0.
readyIndexed. chunk_count is greater than 0 and the document can be cited.
failedPermanently failed; error says why and chunk_count is 0. Delete it and upload a corrected file or re-crawl.

A document's status changes only through its job. Poll the job (or wait for its webhook) rather than polling individual documents.

List documents

curl -s "https://api.chatbots.ecourtdate.com/v1/documents?namespace=general&status=ready&limit=2" \
-H "Authorization: Bearer $API_KEY"
{
"object": "list",
"data": [
{
"id": "9a7e5d21-53c4-4b8a-a0e1-2c7f3b4d5e6f",
"object": "document",
"namespace": "general",
"filename": "jury-duty-faq.md",
"source_type": "upload",
"source_url": null,
"status": "ready",
"chunk_count": 5,
"error": null,
"created_at": "2026-08-21T14:03:11.214000Z",
"updated_at": "2026-08-21T14:03:16.030000Z"
},
{
"id": "17136f01-972d-4956-868e-8159833072e4",
"object": "document",
"namespace": "general",
"filename": "traffic-division-faq.pdf",
"source_type": "upload",
"source_url": null,
"status": "ready",
"chunk_count": 18,
"error": null,
"created_at": "2026-08-21T14:03:11.214000Z",
"updated_at": "2026-08-21T14:03:42.908000Z"
}
],
"first_id": "9a7e5d21-53c4-4b8a-a0e1-2c7f3b4d5e6f",
"last_id": "17136f01-972d-4956-868e-8159833072e4",
"has_more": true
}

Documents are sorted by created_at, newest first (ties are broken by id, descending, so the order is stable across pages). Documents from one upload request share a created_at, so within that request they are ordered by id, not by the order the files were sent, as the two documents above show.

Query parameters

ParameterTypeDescription
limitintegerPage size, 1 to 1000. Default 100.
afterstringCursor: the last_id of the previous page. Returns the documents that follow it in the sort order. Must be the id of one of your documents.
namespacestringOnly documents in this namespace (exact, case-sensitive match). An empty value is 400.
statusstringOnly documents in this status: processing, ready, or failed.
source_typestringOnly documents of this origin: upload or crawl.

Filters combine with AND. A limit outside 1 to 1000 (or not an integer), an empty after, an after that is not one of your documents, an empty namespace, or an unknown status or source_type value returns 400 with param naming the parameter:

{
"error": {
"message": "Unknown document id in `after`: '4b1f0c8e-2a77-4c0f-9d3e-6f2a1b9c7d10'.",
"type": "invalid_request_error",
"param": "after",
"code": null
}
}

Response

FieldTypeDescription
objectstringAlways list.
dataobject[]Up to limit document objects. Empty when nothing matches.
first_idstring or nullid of the first document in data; null when data is empty.
last_idstring or nullid of the last document in data; null when data is empty.
has_morebooleantrue when more documents follow the last one in data.

Paging through every document

Pass the previous page's last_id as after until has_more is false. The filters must stay the same across pages.

curl -s "https://api.chatbots.ecourtdate.com/v1/documents?namespace=general&limit=100&after=17136f01-972d-4956-868e-8159833072e4" \
-H "Authorization: Bearer $API_KEY"
import os
import requests

API_KEY = os.environ["API_KEY"]
BASE_URL = "https://api.chatbots.ecourtdate.com/v1"

def list_documents(**filters):
params = {"limit": 100, **filters}
while True:
r = requests.get(
f"{BASE_URL}/documents",
headers={"Authorization": f"Bearer {API_KEY}"},
params=params,
)
r.raise_for_status()
page = r.json()
yield from page["data"]
if not page["has_more"]:
return
params["after"] = page["last_id"]

failed = [d for d in list_documents(namespace="general", status="failed")]
for doc in failed:
print(doc["id"], doc["filename"], doc["error"])

Because the list is sorted newest first and paged by id, documents created while you are paging appear at the front and are not included in pages you have already fetched; start over to pick them up.

Retrieve a document

curl -s "https://api.chatbots.ecourtdate.com/v1/documents/17136f01-972d-4956-868e-8159833072e4" \
-H "Authorization: Bearer $API_KEY"

Returns the document object. An unknown id, an id belonging to another account, or an already-deleted id all return the same 404 not_found:

{
"error": {
"message": "Document not found.",
"type": "invalid_request_error",
"param": null,
"code": "not_found"
}
}

Citations carry the document_id of the chunk they came from, so this endpoint is the way to turn a citation into the document's current filename, URL, and status.

Delete a document

curl -s -X DELETE "https://api.chatbots.ecourtdate.com/v1/documents/17136f01-972d-4956-868e-8159833072e4" \
-H "Authorization: Bearer $API_KEY"
{
"id": "17136f01-972d-4956-868e-8159833072e4",
"object": "document.deleted",
"deleted": true,
"chunks_deleted": 18
}
FieldTypeDescription
idstringThe deleted document's id.
objectstringAlways document.deleted.
deletedbooleanAlways true on a 200.
chunks_deletedintegerNumber of indexed chunks removed. 0 for a document that was never indexed (processing or failed).

Deletion is synchronous and irreversible. It removes, in order:

  1. The indexed chunks, so the document stops being retrieved and cited immediately.
  2. The stored copy: the uploaded file for an upload, or the archived page HTML for a crawled page.
  3. The document record, so the id returns 404 from then on.

Deleting is not idempotent at the status level: a second DELETE on the same id returns 404 not_found, which a client can safely treat as "already gone".

Do not delete a document whose job is still processing. The delete succeeds (with chunks_deleted: 0), but when the job reaches that document it is counted as failed and recorded in the job's errors[] with the message Document was deleted before it was processed. (no document remains to carry the error). Wait for a terminal job status first.

There is no bulk delete. To clear a namespace, page through it and delete each document. Each delete counts against your per-minute request budget (Rate limits), so honor Retry-After on 429.

def delete_namespace(namespace):
for doc in list(list_documents(namespace=namespace)):
r = requests.delete(
f"{BASE_URL}/documents/{doc['id']}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
if r.status_code == 404:
continue # already deleted
r.raise_for_status()

Errors

StatusCodeWhen
400nullGET /v1/documents with a limit outside 1 to 1000, an empty or unknown after, an empty namespace, or an unknown status or source_type value; param names the parameter.
401invalid_api_keyMissing or invalid key.
403insufficient_scopeThe key lacks the ingest scope.
404not_foundGET or DELETE on an unknown, deleted, or other-account document id.
429rate_limit_exceeded, insufficient_quotaPer-minute request limit or daily token quota reached; honor Retry-After.

All errors use the standard envelope described in Errors.