Skip to main content
Workspace admin

Query endpoints

Two endpoints, one request shape. Both need a scoped token — see Issue a scoped token — and both are stateless: each call is answered on its own, with no memory of the last one.

Ask a question

curl -X POST "$BASE_URL/kb-api/api/v1/kb/$KB_ID/widget/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"question": "What is the notice period for a fixed-term contract?"}'

Request

FieldTypeNotes
questionstringRequired. The question, in plain language. Note the name — it is not query.
top_kintegerHow many passages to retrieve before answering. Optional; the service picks a sensible number.
optionsobjectReserved for per-call tuning. Optional.
conversation_idstringAccepted and ignored. These endpoints hold no conversation.

Response

{
"answer": "A fixed-term contract requires 30 days' written notice…",
"citations": [
{ "index": 1, "doc_id": "doc_01J…", "kb_id": "kb_01J…", "source_span": { } }
],
"provenance": "generated",
"abstained": false
}
FieldTypeNotes
answerstringThe grounded answer. When abstained is true, this is the refusal message.
citationsarrayWhat the answer was drawn from. Empty when nothing was cited.
citations[].indexintegerThe marker used in answer.
citations[].doc_idstringThe document the passage came from.
citations[].kb_idstringThe knowledge base it belongs to.
citations[].source_spanobjectOpaque locator for the passage. Pass it back to us when reporting a problem; do not parse it.
provenancestringgenerated, abstained or qa_shortcut.
abstainedbooleanTrue when Elie declined to answer.

Fields with no value are omitted rather than sent as null.

An abstention is a success, not an error. It arrives as 200 with abstained: true, and it means the knowledge base held no evidence good enough to answer from. Treat it as an answer your interface should show, not as a failure to retry.

Stream the answer

curl -N -X POST "$BASE_URL/kb-api/api/v1/kb/$KB_ID/widget/query/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"question": "What is the notice period?"}'

Same request body. The response is text/event-stream, and every frame carries a JSON object whose type repeats the event name.

EventPayloadWhat to do with it
token{ "type": "token", "text": "…" }Append text to what you are showing.
citations{ "type": "citations", "citations": [ … ] }Render the sources. Same fields as above, plus text when the passage is quotable. May arrive before the answer finishes.
abstain{ "type": "abstain", "answer": "…" }Replace everything shown so far with answer.
reset{ "type": "reset" }Discard everything shown so far and keep listening.
suggestions{ "type": "suggestions", "questions": [ … ] }Optional follow-up questions to offer.
done{ "type": "done", "abstained": false }The answer is complete. Close the stream.
error{ "type": "error", "code": "…", "message": "…" }Generation failed part-way. Show what you have, plus a failure notice.

Handle reset and abstain or you will show text that Elie has withdrawn. Both exist precisely because the service may retract a partial answer it no longer stands behind.

A refused request never becomes a stream: authentication and access are checked before the response opens, so you get an ordinary status code and a JSON body instead.

Next

Steps verified on . Something wrong with this page?