Tether
DocsGitHub

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
}
FieldNotes
nameRequired. 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
formattext (the default) or markdown. Markdown is kept as written; its headings help retrieval
textRequired. At most 50,000 characters by default. One document may hold several languages: Georgian and English side by side is fine
replacetrue to replace a document already held under this name
sourceOptional. 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

LimitDefaultWhen reached
Documents per business20409 knowledge_limit_reached. Replacing a document does not count twice
Characters per document50,000413 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.knowledge lists 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.