API reference
One endpoint. Cited answers.
Kus exposes a single endpoint. Send a question, get a grounded answer with the passages it came from. There is no SDK to learn and nothing to install.
Authentication
Every request carries your key in the X-API-Key header. Keys are created in the dashboard under API Keys, and the raw value is shown once at creation — store it then. Each key maps to its own tenant, so documents you upload are only ever visible to answers made with that key.
curl -X POST https://kus.26io.com/api/query \
-H "X-API-Key: kus_live_..." \
-H "Content-Type: application/json" \
-d '{
"query": "What is a Python decorator?",
"topic": "tech",
"max_chunks": 5
}'Request
POST /api/query
| Field | Type | Meaning |
|---|---|---|
| query | string, required | The question. 2–4000 characters. |
| topic | string, optional | tech, science or maths — comma-separated for more than one. Auto-detected when omitted. |
| return_answer | boolean, default true | Include the synthesised answer. |
| return_chunks | boolean, default true | Include the supporting source chunks. |
| max_chunks | integer, default 5 | How many chunks to return. Between 1 and 20. |
Response
{
"status": "success",
"query": "What is a Python decorator?",
"answer": "A decorator is a callable that takes a function...",
"domains": ["tech"],
"source": "knowledge_base",
"cached": true,
"confidence": 0.86,
"sufficient_context": true,
"child_rags_triggered": ["tech"],
"workers_used": ["docs", "web"],
"web_rounds": 0,
"response_time_ms": 148,
"chunks": [
{ "text": "...", "source_url": "https://docs.python.org/..." }
]
}| answer | The synthesised answer. Present when return_answer is true. |
| chunks | Supporting passages, each with its text and source_url. |
| domains | Which domains the query was classified into. |
| source | Where the answer came from — knowledge_base, semantic_cache, or web. |
| cached | True when served without a fresh model call. |
| confidence | The synthesiser's own confidence in the answer. |
| sufficient_context | False when Kus judged the evidence too thin to answer well. |
| child_rags_triggered | Which child RAGs the router fanned out to. |
| workers_used | Which source workers contributed. |
| web_rounds | How many agentic web rounds ran. 0 means it answered from what it knew. |
| response_time_ms | Server-side time for the call. |
Read sufficient_context. When it is false, Kus is telling you the evidence was thin — the answer is still returned, but it is the one case worth surfacing to your user rather than passing through silently.
Errors
| HTTP | code | When |
|---|---|---|
| 400 | INVALID_QUERY | Both return_answer and return_chunks were false — there would be nothing to return. |
| 401 | — | Missing or unrecognised X-API-Key. |
| 422 | OUT_OF_SCOPE | The query falls outside the domains Kus covers. |
| 429 | — | Rate limit exceeded. |
| 502 | SYNTHESIS_FAILED | The upstream model failed to produce an answer. |
| 500 | INTERNAL | Unexpected server error. |
Errors return a JSON body shaped { "status": "error", "code": ..., "message": ... }. Requests are rate limited per key; the default allowance is 60 requests a minute.
Using it
import requests
KUS = "https://kus.26io.com"
KEY = "kus_live_..."
def knowledge_search(query, topic=None):
r = requests.post(
f"{KUS}/api/query",
headers={"X-API-Key": KEY},
json={"query": query, "topic": topic},
timeout=60,
)
r.raise_for_status()
return r.json()["answer"]The case Kus is built for is handing it to a smaller model as a tool. Register it like this and let the model call it whenever it is out of its depth:
{
"name": "knowledge_search",
"description": "Search accurate info on tech, science, or maths. Call whenever unsure or lacking knowledge.",
"parameters": {
"query": "string — the specific question to look up",
"topic": "string (optional) — tech | science | maths"
}
}Ready to try it?
Create a key in the dashboard, or run a query in the Playground first — no code needed.