Search and queries
/context is the right call for “what should my agent know.”
These two are for when you want the raw material instead.
Search — passages
Section titled “Search — passages”curl "$API/v1/brains/tenant:acme/search?q=sso+redirect+loop&limit=5" \ -H "authorization: Bearer $NICIA_KEY"{ "data": { "results": [ { "source": "zendesk:ticket:8821", "slug": "brain-evidence-3bb86259c42d0261e0f1cc2d0f7f5f6bb2ee2a9a1cfa8a5b1c5e8a5f0f2a7d31", "title": "SSO login loop after IdP change", "excerpt": "Customer reports a redirect loop after switching to Okta…", "rank": 1, "version": 3 } ], "mode": "fulltext", "staged": 0, "warnings": [], "receipt": "rcp_019fff21" }}Search ranks the passages of everything the Brain holds, best match first. Use
it to build your own retrieval flow, to show a “sources” panel, or to debug why
/context answered the way it did.
rank is a position, not a score: 1 is the best match. Ranking fuses a
keyword leg and a semantic leg into an ORDER, and there is no comparable
relevance number underneath to hand you. version is the exact document
version the passage was cut from, and it is what the receipt records.
source is the id you wrote the document under — the address to act on, and the
one that round-trips into GET /documents/{id}. slug is the Brain’s internal
address for the page (a content hash for anything written through this API), and
it is what lets you line a hit up against a /context citation.
mode is the whole narrowing vocabulary:
mode |
Ranks by |
|---|---|
fulltext (default) |
Keywords. No embedding round trip, so it is the fast path |
hybrid |
Keywords and meaning, fused — matches phrasings you did not use |
The response echoes the mode it actually ranked by. hybrid needs an
embedding provider, and a deployment without one answers your hybrid request
with keyword ranking rather than failing a read it can still serve — so
data.mode comes back fulltext and you can tell a fused answer from a
keyword one. Check it before you conclude that semantic matching did not help.
Search takes no filter, exactly like /context.
Ranking reads a passage index, and that index knows nothing about your document
metadata. When you want a slice rather than a ranking — this kind, this field,
this value — that is /query below. Ranked retrieval and exact predicates are
different tools, and Nicia will not pretend one is the other by accepting a
filter it cannot apply.
Query — rows
Section titled “Query — rows”When you want exact answers over typed fields rather than ranked passages:
curl -X POST "$API/v1/brains/tenant:acme/query" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "kind": "person", "where": { "role": "VP Platform" }, "limit": 20 }'{ "data": { "records": [ { "id": "bob-smith", "kind": "person", "fields": { "name": "Bob Smith", "role": "VP Platform" }, "sources": ["zendesk:ticket:8821"], "version": 3, "updatedAt": "2026-08-02T14:20:00Z" } ], "staged": 0, "warnings": [], "receipt": "rcp_019fff44" }}where filters on fields, and it is exact by construction. A scalar is
equality; { "has": … } matches one element of a string_list field. Every
predicate you send is AND-ed, up to eight of them:
{ "kind": "person", "where": { "role": "VP Platform", "regions": { "has": "emea" } }, "limit": 50}has is element equality, not substring: { "has": "emea" } matches the list
["emea", "apac"] and does not match "emea-north". Nothing is normalized
either — no case folding, no trimming — because an answer that depends on a
rule you cannot see is not an exact answer.
Exact is the whole vocabulary. There is no range, no or, no ordering, and no
traversal over links; a where carrying one is a 400 naming the field rather
than a page that silently came back empty. Filter what the Brain can filter,
sort on your side.
Only declared fields are queryable. Anything you sent that the schema does not
declare is still stored and still returned on the record — it just cannot be
filtered on until you declare it, and a predicate against it is that same 400.
See Schemas.
Paging
Section titled “Paging”/query is keyset-paged with an opaque cursor. Its limit may ask for at most
100 records — that is the reader’s page, and a larger one is a 400 rather
than a page quietly cut down to size:
curl -X POST "$API/v1/brains/tenant:acme/query" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "kind": "person", "cursor": "eyJrIjoi…" }'{ "data": { "records": [], "staged": 0, "warnings": [], "receipt": "rcp_019fff44", "nextCursor": "eyJrIjoi…" }}Cursors are stable under concurrent writes: a record added mid-walk will not shift the page boundary and cause you to skip one.
/search is not paged. It is a ranked top-N read with no stable cursor to
hand out, so it takes a limit of at most 20 and returns the best matches for
your query. Ask a narrower question rather than walking a ranking — a cursor
here would have served you the same first page over and over.
Receipts
Section titled “Receipts”Search and query both issue receipts, exactly like /context. Anything that
shows a customer information can be reconstructed later, whichever endpoint
produced it. See Receipts.
Which one do I want?
Section titled “Which one do I want?”- Putting knowledge in a prompt →
/context. It selects, budgets, and renders for you. - Showing sources, or building your own selection →
/search. - Populating a table, a dashboard, or a business rule →
/query.
If you are reaching for /search to then paste the results into a prompt, use
/context with format: "items" instead — you get the same pieces plus the
budgeting.