API reference
Knowledge
/v1/knowledge holds a business's own documents: its refund rules, cancellation policy, delivery
terms, opening hours, FAQ. The agent retrieves the passages a question needs and says which
documents it drew on. A document can tell the agent what the rule is. It cannot tell it whether
this booking or this order qualifies; that is still a question for your tools.
All three routes take the tenant's secret key. A publishable or agent key is refused with
403 insufficient_scope. A repository's CI key (tci_) may
list documents and upload one that carries a repository source, and replace one it holds only
if it was issued with allowReplace; it cannot delete one.
Upload a document
curl -X POST $TETHER_URL/v1/knowledge \
-H "X-Api-Key: $TETHER_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "cancellation-policy",
"format": "markdown",
"text": "# ჯავშნის გაუქმების წესი\n\nჯავშნის გაუქმება უფასოა, სანამ ის დაიწყება.\n\n# Cancellation policy\n\nA booking can be cancelled free of charge until it starts."
}'
{
"name": "cancellation-policy",
"format": "markdown",
"version": 1,
"chars": 152,
"chunks": 1,
"embeddedChunks": 1,
"status": "embedded",
"updatedAt": "2026-10-15T09:12:44Z",
"copiedFrom": null,
"source": null,
"replaced": false
}
| Field | Notes |
|---|---|
name | Required. 1 to 80 letters, digits, -, _ or ., starting with a letter or digit. It is how the document is named on every answer that drew on it |
format | text (the default) or markdown. Markdown is kept as written; its headings help retrieval |
text | Required. At most 50,000 characters by default. One document may hold several languages: Georgian and English side by side is fine |
replace | true to replace a document already held under this name |
source | Optional. Where the text came from: {"kind": "repository", "commit": "<git commit id>", "path": "docs/cancellation-policy.md", "dirty": false}. Kept with this version and shown on GET; see below |
Where a document came from
source records which commit of your own repository a document was published from, as
tether publish sends it. kind is
repository; commit is 7 to 64 lowercase hexadecimal characters; path, optional, is the
file's path inside the repository (relative, with /, at most 300 characters); dirty, optional,
is true when the checkout differed from that commit. Any other field, or a malformed one, is
refused with 400 invalid_source, naming the field. The source belongs to the version it was sent
with: replacing the document without one leaves it null. Nothing reads it to decide anything; a
provider's template copy carries it to each business with the document.
Replacing is explicit
A second upload under a name you already hold is refused with 409 knowledge_document_exists, so
two people cannot overwrite each other's policy by accident. Send "replace": true to replace it.
Every chunk of the old text is removed and the new text stored in one step, the version goes up by
one, and the response says "replaced": true. Uploads to one business are applied one at a time,
so two racing uploads of the same name store one document, never a mixture.
Limits
| Limit | Default | When reached |
|---|---|---|
| Documents per business | 20 | 409 knowledge_limit_reached. Replacing a document does not count twice |
| Characters per document | 50,000 | 413 knowledge_too_large |
Text is split into chunks of about 900 characters, with a little overlap, and each chunk is
embedded. If the embedding call fails, or the deployment has no embedding provider, the text is
stored anyway and the document's status is text_only: it is still found, by keyword.
List documents
curl $TETHER_URL/v1/knowledge -H "X-Api-Key: $TETHER_SECRET_KEY"
{
"documents": [
{
"name": "cancellation-policy",
"format": "markdown",
"version": 2,
"chars": 152,
"chunks": 1,
"embeddedChunks": 1,
"status": "embedded",
"updatedAt": "2026-10-15T09:20:03Z",
"copiedFrom": null,
"source": null
}
],
"count": 1,
"limits": { "maxDocuments": 20, "maxDocumentChars": 50000 }
}
status is embedded (every chunk has an embedding), text_only (none has; keyword retrieval
only) or partially_embedded. To embed a text_only document once a provider is configured,
upload it again with replace.
Delete a document
curl -X DELETE $TETHER_URL/v1/knowledge/cancellation-policy -H "X-Api-Key: $TETHER_SECRET_KEY"
{ "deleted": true, "name": "cancellation-policy", "chunks": 1 }
Every chunk is removed from the database, not hidden, and the next turn draws on none of it. A
name you do not hold answers 404 knowledge_document_not_found.
What a turn does with it
On every turn that reaches the model, the passages that match the question are retrieved, from your documents and from nothing of any other business's.
-
Beside your tools, never instead of them. A turn that draws on a document is offered every tool it would have been offered without it. "What is your cancellation policy?" can be answered from the document; "can I still cancel B101?" is answered by your booking tool, and the document explains the rule.
-
Named on the answer.
meta.knowledgelists the documents the turn drew on, by name. It is absent when the turn drew on none.{ "meta": { "knowledge": ["cancellation-policy"], "customer_language": "ka", "reply_language": "ka" } } -
Not a preview. Unlike Preview Mode's crawled pages, an answer from your documents is not flagged
preview. They are yours, not guessed from a public page. -
Data, not instructions. Retrieved text is fenced as untrusted data in the model's prompt, like every tool result and retrieved page, and the model is told a document states a policy but never the state of a particular record, and never permits an action your tools and approval policy do not.
Georgian
Retrieval works in Georgian whichever way the customer types it. With an embedding provider, the
question and the passages are compared by meaning. Without one, retrieval is by keyword, and it
reads a question typed in Latin letters (ra aris javshnis gauqmebis wesi?) in Georgian script, as
routing does, and matches a word across its case endings (ჯავშნის, ჯავშანი). So a Georgian
policy is found by a Georgian-script question and by a Latin-typed one.
How well the model then answers from a document has not been graded with a live model.
From a provider's template
A provider can upload documents to its own tenant. They are part of the
configuration its businesses start from: each is copied into a new business, embeddings and all,
and copied again when the provider re-applies its configuration (part knowledge:<name>). A copy
replaces the business's document of the same name and leaves its other documents alone. It shows
copiedFrom in the list, and the business may delete it.
Related
- Context and memory — where knowledge is stored
- Chat —
meta.knowledgeon the response - Errors — every code these routes return