Skip to content

Query & Search API

Base path: /api/v1/query

This module handles all natural-language interaction with the knowledge base: asking questions (RAG), semantic search, query history, documentation gap tracking, and aggregate analytics.

See API Reference for auth, errors, and pagination.


POST /api/v1/query/ask

Submit a natural language question and receive a RAG-generated answer with source citations.

The service embeds the question, retrieves the most relevant knowledge chunks from the organisation's knowledge base, and synthesises a grounded answer using an LLM. The interaction is persisted as a QueryLog record. If no relevant knowledge is found, the question is logged as a documentation gap.

Auth: JWT required — any active user (member, manager, or admin). All plans.

Request body (application/json)

Field Type Required Constraints Description
query_text string Yes 1–2000 chars, non-blank Natural language question (Arabic or English)
{
  "query_text": "What is the return policy for damaged goods?"
}

Response 200 OK

Field Type Description
answer string LLM-generated answer grounded in knowledge base sources
sources SourceCitation[] List of knowledge entries cited in the answer
confidence string high | medium | low | none — derived from source quality
language string Detected language of the question: ar | en | mixed
query_id string (UUID) ID of the persisted QueryLog record

SourceCitation object

Field Type Description
entry_id string UUID of the cited KnowledgeEntry
title string Title of the knowledge entry
relevance_score float 0.0–1.0 cosine similarity score
{
  "answer": "Damaged goods may be returned within 30 days of purchase with original packaging. Contact support@example.com to initiate the process.",
  "sources": [
    {
      "entry_id": "a1b2c3d4-0000-0000-0000-000000000001",
      "title": "Return & Refund Policy",
      "relevance_score": 0.94
    },
    {
      "entry_id": "a1b2c3d4-0000-0000-0000-000000000002",
      "title": "Customer Support Procedures",
      "relevance_score": 0.78
    }
  ],
  "confidence": "high",
  "language": "en",
  "query_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}

Errors

HTTP Code Cause
400 VALIDATION_ERROR query_text is missing, blank, or > 2000 chars
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND Authenticated user does not exist or is inactive
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl -X POST https://api.knora.io/api/v1/query/ask \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"query_text": "What is the return policy for damaged goods?"}'

GET /api/v1/query/search

Perform a semantic (vector) search over the organisation's knowledge base and return the top-K most similar chunks — without invoking an LLM. Use this endpoint when you want raw similarity results rather than a synthesised answer, e.g. for suggestions, autocomplete, or building custom UI experiences.

Auth: JWT required — any active user. All plans.

Query parameters

Parameter Type Required Default Constraints Description
q string Yes Non-empty Search text
limit integer No 20 1–50 Maximum number of results to return
department string No Filter results to a specific department name

limit is clamped server-side to [1, 50]. The department filter is applied after visibility checks.

Response 200 OK

Field Type Description
query string The search text that was submitted
results SearchResult[] Ranked list of matching knowledge chunks
total integer Number of results returned

SearchResult object

Field Type Description
entry_id string UUID of the parent KnowledgeEntry
title string Title of the entry
similarity_score float 0.0–1.0 cosine similarity
chunk_text string The matching text chunk
department string | null Department the entry belongs to, if set
language string | null Language of the chunk (ar, en, etc.)
{
  "query": "vacation request process",
  "results": [
    {
      "entry_id": "b2c3d4e5-0000-0000-0000-000000000001",
      "title": "HR Leave Management Policy",
      "similarity_score": 0.91,
      "chunk_text": "Annual leave requests must be submitted at least two weeks in advance via the HR portal...",
      "department": "Human Resources",
      "language": "en"
    }
  ],
  "total": 1
}

Errors

HTTP Code Cause
400 VALIDATION_ERROR q parameter is missing or empty
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND User does not exist or is inactive
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl "https://api.knora.io/api/v1/query/search?q=vacation+request+process&limit=10&department=Human+Resources" \
  -H "Authorization: Bearer <token>"

GET /api/v1/query/history

Return the authenticated user's own recent query history. Each item represents one question the user submitted via /ask.

Auth: JWT required — any active user (own history only). All plans.

Query parameters

Parameter Type Required Default Constraints Description
limit integer No 50 1–100 Maximum number of history items to return

limit is clamped server-side to [1, 100]. Results are returned in reverse chronological order.

Response 200 OK

Field Type Description
items QueryHistoryItem[] Ordered list of recent queries
total integer Number of items returned

QueryHistoryItem object

Field Type Description
id string UUID of the QueryLog record
query_text string The original question text
language string Detected language: ar | en | mixed
has_answer boolean Whether the query received an LLM answer
source_count integer Number of knowledge entries cited in the answer
created_at string ISO 8601 timestamp of when the query was submitted
{
  "items": [
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "query_text": "What is the return policy for damaged goods?",
      "language": "en",
      "has_answer": true,
      "source_count": 2,
      "created_at": "2026-05-31T14:22:10Z"
    },
    {
      "id": "c1d2e3f4-0000-0000-0000-000000000001",
      "query_text": "كيف أطلب إجازة سنوية؟",
      "language": "ar",
      "has_answer": false,
      "source_count": 0,
      "created_at": "2026-05-31T09:05:44Z"
    }
  ],
  "total": 2
}

Errors

HTTP Code Cause
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND User does not exist or is inactive
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl "https://api.knora.io/api/v1/query/history?limit=25" \
  -H "Authorization: Bearer <token>"

GET /api/v1/query/gaps

List unresolved documentation gaps — queries that were submitted but could not be answered because no relevant knowledge was found. Gaps are automatically created by the /ask endpoint. Use this endpoint to understand what knowledge your organisation is missing and prioritise content creation.

Auth: JWT required — manager or admin only. All plans.

Query parameters

Parameter Type Required Default Constraints Description
department string No Filter gaps to a specific department
limit integer No 100 1–500 Maximum number of gaps to return

limit is clamped server-side to [1, 500]. Only unresolved gaps are returned.

Response 200 OK

Field Type Description
items GapResponse[] List of unresolved gap records
total integer Number of items returned

GapResponse object

Field Type Description
id string UUID of the gap log record
query_text string The original question that could not be answered
user_id string | null UUID of the user who asked the question
department string | null Department context of the gap, if available
resolved boolean Whether the gap has been resolved
resolved_by_entry_id string | null UUID of the KnowledgeEntry that resolved this gap
created_at string ISO 8601 timestamp when the gap was first logged
{
  "items": [
    {
      "id": "d4e5f6a7-0000-0000-0000-000000000001",
      "query_text": "كيف أطلب إجازة سنوية؟",
      "user_id": "e5f6a7b8-0000-0000-0000-000000000001",
      "department": "Human Resources",
      "resolved": false,
      "resolved_by_entry_id": null,
      "created_at": "2026-05-31T09:05:44Z"
    }
  ],
  "total": 1
}

Errors

HTTP Code Cause
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND User does not exist or is inactive
403 INSUFFICIENT_ROLE Caller is a plain member
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl "https://api.knora.io/api/v1/query/gaps?department=Finance&limit=50" \
  -H "Authorization: Bearer <token>"

POST /api/v1/query/gaps/:gap_id/resolve

Mark a documentation gap as resolved by linking it to an existing KnowledgeEntry. This signals that the missing content has been created, allowing the gap to be tracked as closed.

Auth: JWT required — manager or admin only. All plans.

Path parameters

Parameter Type Description
gap_id UUID ID of the gap record to resolve

Request body (application/json)

Field Type Required Description
entry_id string Yes UUID of the KnowledgeEntry that resolves this gap
{
  "entry_id": "a1b2c3d4-0000-0000-0000-000000000005"
}

Response 200 OK

Returns the updated GapResponse object (see /gaps above) reflecting the resolved state, with resolved: true and resolved_by_entry_id populated.

{
  "id": "d4e5f6a7-0000-0000-0000-000000000001",
  "query_text": "كيف أطلب إجازة سنوية؟",
  "user_id": "e5f6a7b8-0000-0000-0000-000000000001",
  "department": "Human Resources",
  "resolved": true,
  "resolved_by_entry_id": "a1b2c3d4-0000-0000-0000-000000000005",
  "created_at": "2026-05-31T09:05:44Z"
}

Errors

HTTP Code Cause
400 VALIDATION_ERROR entry_id is missing or is not a valid UUID
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND User does not exist or is inactive
403 INSUFFICIENT_ROLE Caller is a plain member
404 GAP_NOT_FOUND gap_id does not exist within this organisation
404 ENTRY_NOT_FOUND entry_id does not exist or belongs to a different org
409 GAP_ALREADY_RESOLVED The gap has already been resolved
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl -X POST "https://api.knora.io/api/v1/query/gaps/d4e5f6a7-0000-0000-0000-000000000001/resolve" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"entry_id": "a1b2c3d4-0000-0000-0000-000000000005"}'

GET /api/v1/query/analytics

Return aggregate statistics about query activity and documentation gap coverage for the organisation. Useful for dashboards, health reporting, and prioritising knowledge base growth.

Auth: JWT required — admin only. Plan check fires before role checktrial and starter organisations receive 403 PLAN_UPGRADE_REQUIRED regardless of role.

No query parameters or request body.

Response 200 OK

Field Type Description
total_queries integer Total questions submitted by all users in the organisation
answered_queries integer Queries that received an LLM answer with at least one source
unanswered_queries integer Queries that received no answer (became gaps)
answer_rate float Fraction 0.0–1.0 of queries that were answered (answered / total)
total_gaps integer Total number of gap records ever logged
resolved_gaps integer Gaps that have been linked to a resolving KnowledgeEntry
unresolved_gaps integer Gaps still awaiting resolution
top_unanswered_topics TopicCount[] Most frequently occurring unanswered query clusters (up to 10)

answer_rate is 0.0 when total_queries is 0. top_unanswered_topics is empty if no unanswered queries exist.

TopicCount object

Field Type Description
topic string Representative query text for the cluster
count integer Number of times this topic was asked unanswered
{
  "total_queries": 1240,
  "answered_queries": 1058,
  "unanswered_queries": 182,
  "answer_rate": 0.853,
  "total_gaps": 182,
  "resolved_gaps": 74,
  "unresolved_gaps": 108,
  "top_unanswered_topics": [
    { "topic": "expense reimbursement process", "count": 23 },
    { "topic": "parental leave policy", "count": 17 },
    { "topic": "remote work equipment allowance", "count": 11 }
  ]
}

Errors

HTTP Code Cause
401 INVALID_TOKEN JWT missing or malformed
401 USER_NOT_FOUND User does not exist or is inactive
403 PLAN_UPGRADE_REQUIRED Organisation is on trial or starter plan (checked first)
403 INSUFFICIENT_ROLE Caller is member or manager (admin required)
402 SUBSCRIPTION_REQUIRED Organisation subscription is inactive
curl "https://api.knora.io/api/v1/query/analytics" \
  -H "Authorization: Bearer <token>"