Chat
Ask questions answered from the collection, with cited sources.
Base URL https://futuresmart.ai/document-intelligence/api · every request sends x-api-key. Samples read the key from DOCUMENT_INTELLIGENCE_API_KEY. All endpoints
Ask a question
/v1/{knowledge_id}/chatChat over a knowledge base's indexed documents.
Runs chat/graph.py's query_refiner -> rag graph. Persists the turn to knowledge_chat_sessions/knowledge_chat_logs (session ownership: this service, per the plan's "Who calls this endpoint" §3, Option (a)). Streams via SSE when request.stream is true (default); returns a single JSON ChatResponse otherwise. 404s if knowledge_chat_config.chat_enabled is explicitly false for this knowledge_id.
Credential Document Intelligence API key (x-api-key)
Path parameters
| Name | Type | Description |
|---|---|---|
knowledge_idrequired | string |
Request body · application/json
| Name | Type | Description |
|---|---|---|
queryrequired | string | User's chat query. Already description-enriched if an image was sent to the caller — vision handling stays upstream, see the plan's Vision section. |
owner_id | string | null | Owner of the knowledge base, for owner LLM credentials and usage attribution. Resolved from knowledge_config when omitted. |
session_id | string | null | Chat session id. Omit to start a new session (a fresh id is minted and returned). |
user_id | string | null | Acting user, for audit. Distinct from owner_id. Resolved from the caller's session when omitted. |
stream | boolean | Stream the answer via SSE. When false, the full response is returned as one JSON object. |
has_attachment | boolean | Whether an image was attached to this turn upstream. The query above is already description-enriched — this is a transcript-completeness flag only. |
attachment_url | string | null | URL of the attached image, if any, for transcript/audit purposes only. |
from_widget | boolean | Set by the website chat bubble. Records the session's origin as "widget" even when the visitor is signed in — a credential-less caller is already detectable server-side, a signed-in one is not, so only the embed can tell us. See SessionSummary.source. |
from_full_screen | boolean | Set by the full-screen chat embed. For a credential-less caller, gates the request against fullscreen_is_public + fullscreen_allowed_domains instead of the widget's is_public + allowed_domains. |
provider | string | null | LLM provider override applied to every node. Falls through to knowledge_chat_config / env / hardcoded default when omitted. Prefer node_configs when nodes differ. |
model | string | null | LLM model override applied to every node, e.g. 'gpt-5.4-mini'. |
temperature | number | null | Temperature override applied to every node. Accepted but not yet applied downstream (see NodeConfig.temperature). |
max_tokens | integer | null | Max output tokens override. Only meaningful for the generate_answer node; see NodeConfig.max_tokens. |
system_prompt | string | null | System prompt suffix applied to the RAG answer. Equivalent to node_configs.rag_agent.prompt; node_configs wins if both are sent. |
node_configs | object | null | Per-node LLM config, keyed by node name. Accepted keys: 'rag_agent' (the retrieval ReAct loop), 'generate_answer' (the answer writer), 'refined_query_node' (the query rewriter). Any other key is a 422 — see SUPPORTED_NODES for why the Orchestrator's 'supervisor'/'response_node' have no counterpart here. Takes precedence over the flat provider/model/temperature/system_prompt fields for the nodes it names; unnamed nodes fall back to those flat fields, then to the DB row / env / default. |
Other responses
422Validation Error
Example request body
{
"node_configs": {
"generate_answer": {
"model": "gemini-2.5-flash",
"prompt": "Answer only from the retrieved context. Include any ClickUp URLs found.",
"provider": "google"
},
"rag_agent": {
"model": "gpt-5.4-mini",
"prompt": "Prioritise accuracy and completeness in retrieval.",
"provider": "openai"
},
"refined_query_node": {
"model": "gpt-4o-mini",
"provider": "openai"
}
},
"owner_id": "owner-123",
"query": "What invoices do we have from March?",
"stream": true,
"user_id": "user-456"
}List conversations
/v1/{knowledge_id}/sessionsList a knowledge base's chat sessions, most recently active first.
Powers two screens. The Conversations rail (the owner's own threads): search,
date-range filter, per-session exchange counts. And Share -> Activity, which asks
the opposite question — what other people did with a shared collection — via
source/exclude_user_id.
Every filter and the sort are applied in SQL, so one tab is one query:
total_count is that tab's real total and a page is a page of the filtered
result. (Before this, a caller had to split and re-count a page in the browser,
which meant a page of 20 could render 3 rows and the counts described the page
rather than the collection.)
Credential Document Intelligence API key (x-api-key)
Path parameters
| Name | Type | Description |
|---|---|---|
knowledge_idrequired | string |
Query parameters
| Name | Type | Description |
|---|---|---|
page | integer | |
page_size | integer | |
from | string (date-time) | null | ISO 8601. Filter to sessions created on/after this time. |
to | string (date-time) | null | ISO 8601. Filter to sessions created on/before this time. |
q | string | null | Case-insensitive substring match against session_title and every turn's query/response text. |
user_id | string | null | Filter to sessions started by this user. |
source | string | null | Filter by origin: "widget", "dashboard", "api", or "shared" (a dashboard conversation held by somebody other than this collection's current owner). A session recorded before migration 044 has no origin and matches none of these; it still appears when the filter is omitted. |
exclude_user_id | string | null | Drop this person's own conversations. Matched case-insensitively against both user_id and user_email, so either an account id or an email works. |
sort | string | null | Sort key: "last_activity" (default), "questions", "title", "user". An unrecognised value falls back to the default. |
order | string | "asc" or "desc" (default). |
Response · 200
| Name | Type | Description |
|---|---|---|
sessionsrequired | array<SessionSummary> | |
↳ session_idrequired | string | |
↳ title | string | null | session_title if ever set, else the session's first query, truncated to 120 chars. |
↳ exchange_countrequired | integer | |
↳ user_id | string | null | |
↳ user_email | string | null | The caller's address, captured from their session when the conversation started (migration 044). Null for a public/widget visitor, and for any session recorded before that migration — this service cannot resolve an account id to an address after the fact. |
↳ user_name | string | null | Display name from the same session, when the identity provider supplied one. Null otherwise — fall back to user_email, not to the id. |
↳ source | string | null | Where the conversation came from: "widget" (website bubble or full-screen embed), "dashboard" (signed in at a screen), or "api" (master-key integration). Null for sessions recorded before migration 044. Owner-vs-invited is NOT encoded here — use ?source=shared, which derives it from the collection's current owner. |
↳ created_at | string (date-time) | null | |
↳ updated_at | string (date-time) | null | The most recent turn's timestamp. Null only for a session with no turns yet. |
total_countrequired | integer | |
current_pagerequired | integer | |
total_pagesrequired | integer |
Other responses
422Validation Error
Response shape (200)
{
"sessions": [
{
"session_id": "<session_id>",
"exchange_count": 0
}
],
"total_count": 0,
"current_page": 0,
"total_pages": 0
}Get a conversation
/v1/{knowledge_id}/sessions/{session_id}Reopen one session's full transcript, oldest turn first, numbered.
404s for an unknown session_id, a session_id belonging to a different knowledge_id, or a soft-deleted session — all three are "not found" from the caller's side, and get_session_transcript already can't tell them apart from a genuine miss without leaking which knowledge_id a foreign session_id belongs to.
show_sources=False strips relevant_sources/summaries/detailed_chunks from every assistant message here, same as the live /chat response — the DB row (get_session_transcript) always returns the full stored evidence; this endpoint is where that policy is applied for reads, mirroring _build_response_payload's client-facing strip.
Credential Document Intelligence API key (x-api-key)
Path parameters
| Name | Type | Description |
|---|---|---|
knowledge_idrequired | string | |
session_idrequired | string | Session ID |
Response · 200
| Name | Type | Description |
|---|---|---|
session_idrequired | string | |
knowledge_idrequired | string | |
user_id | string | null | |
user_email | string | null | |
user_name | string | null | |
source | string | null | |
title | string | null | |
created_at | string (date-time) | null | |
updated_at | string (date-time) | null | |
exchange_countrequired | integer | |
messagesrequired | array<ChatMessage> | |
↳ nrequired | integer | 1-indexed position of the exchange this message belongs to. |
↳ chat_idrequired | string | |
↳ rolerequired | string | "user" or "assistant" |
↳ messagerequired | string | |
↳ created_at | string (date-time) | null | |
↳ is_answered | boolean | null | |
↳ refined_query | string | null | |
↳ llm_provider | string | null | |
↳ model | string | null | |
↳ user_feedback | string | null | "positive", "negative", or null. Set via PATCH .../messages/{chat_id}/feedback. |
↳ data | object | assistant-only. data.knowledge.{relevant_sources,summaries,detailed_chunks} are genuinely the same fields the live /chat response returns (persisted verbatim by _persist_turn, G14) — not a relabeled stand-in. data.knowledge.knowledge_evidence is a SEPARATE, lossier shape kept for cross-turn memory only; don't treat it as a sources-panel substitute. rag_context is the one live field not persisted. See KnowledgeChatLogs' docstring. |
↳ has_attachment | boolean | |
↳ attachment_url | string | null |
Other responses
422Validation Error
Response shape (200)
{
"session_id": "<session_id>",
"knowledge_id": "<knowledge_id>",
"exchange_count": 0,
"messages": [
{
"n": 0,
"chat_id": "<chat_id>",
"role": "<role>",
"message": "<message>",
"has_attachment": false
}
]
}