Natural-language search over the workspace’s evidence notes AND its finished reports.
Just send text. The default mode is hybrid — bm25 over title/body/tags/summary fused with embedding similarity by reciprocal rank, then weighted by each note’s lifecycle and quality grade. A whole question is a fine query; it is sanitised into a safe FTS5 match, so no punctuation, quoting or operator can fail the request. Quoted spans are honoured as phrases (EU "AI Act" enforcement). A blank text is a filtered listing, not an error.
Ask it as a question if you like. The interrogative frame is stripped before anything is embedded or matched — what did the report on agent protocols conclude? retrieves on agent protocols — so a question and its subject find the same notes. A quoted span survives the strip and is still honoured as a phrase.
Scope it.project (or tag), type, status, domain, since/until all narrow the same search. Finished runs’ reports come back as kind: "report" hits by default, above the notes and inside the same limit; repeated runs of one question collapse to the newest, carrying versions. include_reports=false leaves them out.
Then read. A hit’s id is a note id for POST /v1/vault/notes/batch (up to 50 at once) or GET /v1/vault/notes/{id}; a report hit’s run_id is for GET /v1/runs/{id}/result. Cite source_url.
score is relative to the best hit in THIS result set (1.0 = best here), not an absolute confidence. Results are deduplicated server-side: two runs that read the same page are one row. There is no cursor — raise limit (max 200) or narrow the scope.
Hits carry display_tags beside tags, resolved the same way GET /v1/vault/notes resolves them (E2E5-08). snippet is the excerpt to show: the note’s own summary with the source site’s chrome removed — the same text GET /v1/vault/notes returns as display_summary — falling back to the matched window of the stored body, also cleaned, for a note that has no usable summary, and null when neither holds anything but the site’s furniture (E2E16-01).
Alias for text, accepted for core-interface and MCP clients. text wins if both are sent.
string
<= 2000 characters
Alias for text, accepted for core-interface and MCP clients. text wins if both are sent.
mode
Omit this. The default is hybrid (bm25 + embeddings, reciprocal-rank fused), which is the right answer for a natural-language question and degrades to lexical by itself when the workspace has no embeddings. fts is lexical only and cheaper. semantic is vectors only and fails closed when no embedder is configured.
string
Allowed values: ftssemantichybrid
Omit this. The default is hybrid (bm25 + embeddings, reciprocal-rank fused), which is the right answer for a natural-language question and degrades to lexical by itself when the workspace has no embeddings. fts is lexical only and cheaper. semantic is vectors only and fails closed when no embedder is configured.
tag
One vault tag. project:<id> is a project’s scope — see GET /v1/projects.
string
One vault tag. project:<id> is a project’s scope — see GET /v1/projects.
project
A proj_… id, resolved to its project:<id> tag. The readable spelling of tag for the common case; pass one or the other, not both.
string
A proj_… id, resolved to its project:<id> tag. The readable spelling of tag for the common case; pass one or the other, not both.
status
One note lifecycle: draft|review|evergreen|stale|deprecated|archive.
string
One note lifecycle: draft|review|evergreen|stale|deprecated|archive.
type
One note kind: note|raw|interim|source-analysis|moc|index.
string
One note kind: note|raw|interim|source-analysis|moc|index.
domain
Only notes read from this publisher, e.g. eur-lex.europa.eu. A leading dot (.europa.eu) includes subdomains.
string
<= 255 characters
Only notes read from this publisher, e.g. eur-lex.europa.eu. A leading dot (.europa.eu) includes subdomains.
since
Only notes created at or after this ISO timestamp (a bare date works).
string
<= 64 characters
Only notes created at or after this ISO timestamp (a bare date works).
until
Only notes created at or before this ISO timestamp. Pairs with since to make a range.
string
<= 64 characters
Only notes created at or before this ISO timestamp. Pairs with since to make a range.
include_reports
Whether this workspace’s finished run REPORTS are returned as hits alongside the notes, matched on the question each run asked. Default true: the report is the thing the research produced, and a vault search that returns forty of its sources and not the document itself is answering the wrong question. A report hit carries kind: "report", type: "report" and a run_id/report_id to pass to GET /v1/runs/{id}/result; it is NOT a note id and GET /v1/vault/notes/{id} will not resolve it. Report hits sort above notes of equal score and SHARE the limit with them — a page of six is six rows, however they divide. Repeated runs of one question are one row: it is the newest finished run, and versions says how many runs stand behind it (version_group matches the runs API). Reports take at most half the page unless the query itself says “report”. Pass include_reports=false to get notes only — the thing to do when every id you receive is going straight to a note endpoint.
string
Allowed values: 01truefalse
Whether this workspace’s finished run REPORTS are returned as hits alongside the notes, matched on the question each run asked. Default true: the report is the thing the research produced, and a vault search that returns forty of its sources and not the document itself is answering the wrong question. A report hit carries kind: "report", type: "report" and a run_id/report_id to pass to GET /v1/runs/{id}/result; it is NOT a note id and GET /v1/vault/notes/{id} will not resolve it. Report hits sort above notes of equal score and SHARE the limit with them — a page of six is six rows, however they divide. Repeated runs of one question are one row: it is the newest finished run, and versions says how many runs stand behind it (version_group matches the runs API). Reports take at most half the page unless the query itself says “report”. Pass include_reports=false to get notes only — the thing to do when every id you receive is going straight to a note endpoint.
rank
string
Allowed values: relevancequality
limit
Rows in the response, notes and reports together (default 20, max 200). The two kinds share this budget; they are not two lists of limit.
integer
>= 1<= 200
Rows in the response, notes and reports together (default 20, max 200). The two kinds share this budget; they are not two lists of limit.
The quota policy this request was counted against (draft-ietf-httpapi-ratelimit-headers): "<bucket>";q=<requests>;w=<window seconds>, e.g. "reads";q=60;w=60. Buckets: reads 60/min, status 600/min, creates 10/min, writes 20/min per credential; public 300/min per network on keyless routes.
RateLimit
string
Example
"reads";r=57;t=41
Remaining quota in the current window: "<bucket>";r=<remaining>;t=<seconds until reset>, e.g. "reads";r=57;t=41.
X-RateLimit-Limit
integer
Requests allowed per window in this bucket (legacy form of RateLimit-Policy).
X-RateLimit-Remaining
integer
Requests left in this window (legacy form of RateLimit).
X-RateLimit-Reset
integer
Unix time (seconds) when the window resets.
X-RateLimit-Bucket
string
Which bucket counted the request: reads, status, creates, writes or public.
Seconds to wait before retrying. Always present on a 429.
RateLimit-Policy
string
Example
"reads";q=60;w=60
The quota policy this request was counted against (draft-ietf-httpapi-ratelimit-headers): "<bucket>";q=<requests>;w=<window seconds>, e.g. "reads";q=60;w=60. Buckets: reads 60/min, status 600/min, creates 10/min, writes 20/min per credential; public 300/min per network on keyless routes.
RateLimit
string
Example
"reads";r=57;t=41
Remaining quota in the current window: "<bucket>";r=<remaining>;t=<seconds until reset>, e.g. "reads";r=57;t=41.
X-RateLimit-Limit
integer
Requests allowed per window in this bucket (legacy form of RateLimit-Policy).
X-RateLimit-Remaining
integer
Requests left in this window (legacy form of RateLimit).
X-RateLimit-Reset
integer
Unix time (seconds) when the window resets.
X-RateLimit-Bucket
string
Which bucket counted the request: reads, status, creates, writes or public.