Search
Send a question in everyday language. Knovas returns the documents that match its meaning best.
Run a search
curl -X POST https://api.knovas.ch:8443/secured/query \
--cert client_cert.pem --key client_key.pem --cacert ca_root_cert.pem \
-H "Content-Type: application/json" \
-d '{"Input": "What were the Q3 revenue figures?"}'import requests
BASE = "https://api.knovas.ch:8443"
AUTH = dict(
cert=("client_cert.pem", "client_key.pem"), # your certificate and private key
verify="ca_root_cert.pem", # Knovas' certificate
timeout=60,
)
r = requests.post(f"{BASE}/secured/query", **AUTH, json={"Input": "What were the Q3 revenue figures?"})
r.raise_for_status()
answer = r.json()
for hit in answer["results"]:
print(hit["pointer"], hit["page_number"], round(hit["final_score"], 2))Knovas only ever searches your own documents. The number of results is set by Knovas, not in the request.
Read the results
{
"status": "success",
"query_session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"result_count": 1,
"results": [
{
"pointer": "reports/2025/q3.pdf",
"document_uuid": "550e8400-e29b-41d4-a716-446655440000",
"final_score": 0.91,
"page_number": 3,
"sentence_number": 12,
"snippet": "Revenue by region: EMEA 4.2 million, Americas 3.1 million, Asia 1.8 million"
}
]
}| Field | Meaning |
|---|---|
results | The matching documents, best first. |
pointer | The identifier you gave the document at upload. |
final_score | How well it matches. Higher is better. Use it for sorting, not as a percentage. |
page_number, sentence_number | Where the best passage is (empty if you did not send numbers). |
snippet | The best passage, word for word from the text you uploaded (up to 240 characters). Show it so your users see why the document was found. |
document_uuid | Knovas’ own id for the document. Use it to look up the document’s details. |
query_session_id | The id of this search. Needed if you send feedback. |
Results never contain the full document text. Besides names, scores and locations, the first results each carry a snippet: up to 240 characters of the passage that matched, cut from the text you uploaded (whole rows for tables). With access control, snippets only come from documents the searcher may see. Your own software opens the original document using the pointer.
When nothing is found
You still get a normal answer, with "results": []. Some setups only return results that are clearly relevant; then you may get fewer results than usual, or none, and each result carries relevance_tier (strong or borderline). A search that filters by document fields is always checked this way.
Several phrasings at once
Send a list of questions to search for all of them together. This finds more, and counts as one request against your speed limit:
curl -X POST https://api.knovas.ch:8443/secured/query \
--cert client_cert.pem --key client_key.pem --cacert ca_root_cert.pem \
-H "Content-Type: application/json" \
-d '{"Input": ["Q3 revenue", "third quarter earnings", "sales July to September"]}'import requests
BASE = "https://api.knovas.ch:8443"
AUTH = dict(
cert=("client_cert.pem", "client_key.pem"), # your certificate and private key
verify="ca_root_cert.pem", # Knovas' certificate
timeout=60,
)
r = requests.post(f"{BASE}/secured/query", **AUTH, json={
"Input": ["Q3 revenue", "third quarter earnings", "sales July to September"],
})Find a specific document
You can also ask for a document by name, for example Jahresabschluss Müller AG 2023 or tax return Meier. Knovas matches every search against the titles and paths of your documents as well, so it finds a document by its folder and file name even when the text itself is a poor scan. This works best when the path or title names the client or company and the type of document; see Add documents.
Search on behalf of a user
If you use access control, add access_groups with the groups of the person who is searching. Knovas then only returns documents that person may see.
curl -X POST https://api.knovas.ch:8443/secured/query \
--cert client_cert.pem --key client_key.pem --cacert ca_root_cert.pem \
-H "Content-Type: application/json" \
-d '{"Input": "notice period", "access_groups": ["Legal"]}'import requests
BASE = "https://api.knovas.ch:8443"
AUTH = dict(
cert=("client_cert.pem", "client_key.pem"), # your certificate and private key
verify="ca_root_cert.pem", # Knovas' certificate
timeout=60,
)
r = requests.post(f"{BASE}/secured/query", **AUTH, json={
"Input": "notice period",
"access_groups": ["Legal"], # the groups of the user who is searching
})Filter by document fields
Filtering needs Document fields and field filters. Both are on for every account; where Knovas switched them off, or on an older release:
- Without Document fields, Knovas ignores
whereandreturn_fields. It searches all your documents and the answer has nowheresection. - With Document fields but without field filters, a search with
whereorreturn_fieldsanswers400where_unsupported.
Add where to search only the documents whose typed fields have certain values, for example only the invoices of 2024. Add return_fields to get field values back with each result.
curl -X POST https://api.knovas.ch:8443/secured/query \
--cert client_cert.pem --key client_key.pem --cacert ca_root_cert.pem \
-H "Content-Type: application/json" \
-d '{
"Input": "Telefonkosten",
"where": {
"doc_type": "Rechnung",
"period": "GJ 2024",
"amount": {"gte": "CHF 1'\''000"}
},
"return_fields": ["document_date", "amount"]
}'import requests
BASE = "https://api.knovas.ch:8443"
AUTH = dict(
cert=("client_cert.pem", "client_key.pem"), # your certificate and private key
verify="ca_root_cert.pem", # Knovas' certificate
timeout=60,
)
r = requests.post(f"{BASE}/secured/query", **AUTH, json={
"Input": "Telefonkosten",
"where": {
"doc_type": "Rechnung", # a label of the code "invoice"
"period": "GJ 2024",
"amount": {"gte": "CHF 1'000"},
},
"return_fields": ["document_date", "amount"],
})
r.raise_for_status()
answer = r.json()
# Only treat the results as filtered when Knovas confirms it
if not answer.get("where", {}).get("applied"):
raise RuntimeError("The filter was not applied. Do not show these results as filtered.")
for hit in answer["results"]:
print(hit["pointer"], hit["relevance_tier"], hit.get("fields"))Writing where
- Keys are a field’s key, another name or a label, exactly as in upload
fields. - Values are written as at upload and read by the same rules, so
GJ 2024,März 2024andCHF 1'000all work. See value formats. - All keys must match. A document is found only when it meets every key. There is no “not”.
- Names of clients, courts or parties match documents linked to the knowledge-graph nodes you can see with that name, and documents where the name was stored without a link. Case, accents and spacing do not matter.
- Limits: 8 keys per search and 50 values per list.
| You write | Finds documents where the field… |
|---|---|
"Rechnung" | equals the value. For dates and periods, a plain value means “overlaps”: a document dated 15.03.2024 is found by "2024" and by "März 2024". |
["Rechnung", "Quittung"] | has any of these values. |
{"gte": "01.01.2024"} | is greater than or equal (also gt, lt, lte). For dates, periods, numbers and amounts. Amounts need a currency. |
{"between": ["01.01.2024", "30.06.2024"]} | lies between the two values. |
{"within": "2024"} | lies completely inside the date range. For dates and periods (overlaps also exists). |
{"prefix": "E11"} | starts with this. For codes, choice lists and text. |
{"exists": true} | has any value at all. |
One object can hold several operators, such as {"gte": "CHF 1'000", "lt": "CHF 5'000"}. Stored dates can be ranges too (März 2024 is the whole month). gte and the other comparisons only count a stored range that lies completely on the right side. Add "match": "possible" to also accept ranges that only partly do.
You can combine where with scope and access_groups. A document must then satisfy all of them. Your access comes first: a filter only ever finds documents the user may see.
Check that the filter was applied
where.appliedAn account without field filters, or an older Knovas server, ignores where. It answers with unfiltered results and without a where section. Only treat results as filtered when the answer contains "where": {"applied": true}. Otherwise show no results, or say clearly that the filter was not applied.
"where": {
"applied": true,
"clauses": 3,
"resolved": [
{"field": "doc_type", "op": "eq", "value": "invoice"},
{"field": "period", "op": "eq", "interval": ["2024-01-01", "2024-12-31"]},
{"field": "amount", "op": "gte", "value": {"amount": "1000.00", "currency": "CHF"}}
],
"relevance_gate_applied": true,
"no_strong_matches": false,
"may_be_partial": false
},
"return_fields": {"applied": true}| Field | Meaning |
|---|---|
applied | The filter was applied. Without it, the results are not filtered. |
resolved | How Knovas understood your values. It never shows stored data. For a name it only says how many nodes the name matched (resolved_nodes). |
no_strong_matches | true when no document is relevant enough to show. |
may_be_partial | true when the filter matches more documents than Knovas can search completely. The results are correct, but other matching documents may rank too low to appear. Narrow the filter, or list the matches. |
strategy, exhaustive | Technical details, only returned to a caller who may see every document of your account. |
Only relevant results
A filtered search is always checked for relevance, whatever your account’s own setting. Documents that match the filter but do not answer the question are left out, and every result carries relevance_tier (strong or borderline). If nothing is relevant enough, the answer is empty and says no_strong_matches: true. Knovas does not fill the list with weak matches. To see every document with certain values, without a question, list them instead.
If you filter a client, court or party by node id ({"node_id": …}) and none of those nodes is visible to you, nothing is searched and the answer says no_results_reason: "empty_where".
Field values in results
With return_fields, each result gets a fields section with the values of the document it is returned under. Send a list of field keys (title, description, path and ingested_at work too), or true for all fields plus the title. Fields marked special are only returned when you name them. Names show as written ({"name": …}), and a value set only by node id shows as {"hidden": true}. If the values cannot be read, you still get the results, without fields, and the answer says "return_fields": {"applied": false}. return_fields also works without where.
Errors
| Code | Error | Meaning |
|---|---|---|
400 | where_unsupported | Document fields is on for your account, but field filters are still off. |
400 | unknown_field | A key names no field. suggest may list close keys. |
400 | ambiguous_field | A key names several fields. candidates lists them. |
400 | invalid_value, type_mismatch, checksum_failed, restricted_identifier | A value or operator does not fit the field. path names the key. |
400 | where_too_complex | More than 8 keys, or more than 50 values in a list. |
503 | where_unavailable | The filter could not be checked. Nothing is returned; try again. |
503 | where_requires_calibration | A problem on the Knovas side. Try again later. |
Error answers name the key, never the value you sent.
Automatic narrowing by name
If you use the knowledge graph, Knovas recognises names of your cases or clients inside a question. “What medication does Michael Xample take?” then searches only Michael’s documents. If that finds nothing, Knovas automatically searches everything instead.
When this happened, the answer contains an auto_scope section. If results look unexpectedly narrow, check it first.
Tips for better results
- Search in the language of your documents. German documents are best searched in German.
- Use the words a document would use. “Medication dosage” finds more than “what pills”.
- Send several phrasings in one request (see above).
- Good uploads matter most. Titles and clean text at upload matter more than how the question is phrased. See the upload checklist.
In rare cases Knovas answers with meta.degraded_to_bm25: true. The results are real but were found by exact words only. Try again a little later for full-quality results.
Questions? Write to contact@knovas.ch.
This page describes Knovas 1.6.0. Last updated .