GET /search searches individual messages across all your conversations and returns snippet-level hits. Every result carries a conversation_id + message_index anchor, so you can jump straight to the surrounding turns with GET /conversations/:id/context.
Query parameters
string
required
The search query, 1–500 characters. Leading and trailing whitespace is trimmed; a whitespace-only query returns
400.string
default:"hybrid"
keyword, semantic, or hybrid. Keyword matches literal substrings; semantic matches by meaning; hybrid fuses both. See Search modes.string
Restrict results to conversations from one end user. Maximum 200 characters.
string
default:"all"
One of
all, 1h, 24h, 3d, 7d, 30d, 90d.integer
default:"20"
Maximum results to return, 1–100. There is no
offset — pagination is limit-only.string
default:"false"
true or false. When true, matches inside tool call inputs and tool results are included in the result list.Search modes and degradation
The response always reports which mode actually ran (search_mode) and why, if it differs from what you requested (degrade_reason). A semantic or hybrid request degrades transparently to keyword rather than failing:
Response fields
string
The query as searched (trimmed).
string
The mode that actually ran:
keyword, semantic, or hybrid. May differ from the requested mode.string
none, semantic_unavailable, or below_relevance_floor.array
Ranked hits. Each hit has
conversation_id, message_index, role (user or assistant), timestamp, snippet (the matched text with surrounding context), score, cluster_id and cluster_name (the conversation’s use-case cluster, or null), and conversation_summary (a one-line summary of the conversation, or null). Hits that resolve to a specific content block additionally carry unit_id, content_block_index, block_type, tool_name, and chunk_index.object
Exact counts of distinct conversations containing a literal (case-insensitive) match for the query — independent of the ranked page.
matched_conversations covers the requested window; prior_window_matched_conversations covers the equal-length window immediately before it (null when time_range=all). Either can be null if the count query timed out — a missing number, never a fabricated zero.object
limit (requested page size), returned (hits in this response), and has_more (true when the ranked candidate pool held more hits than the page). There is no offset; to see different results, narrow q, time_range, or user_id.Example
Next steps
- Conversations — fetch windowed context around any search hit.
- Signals — if you are hunting failures, the frustration and tool-failure endpoints already embed context.
- CLI reference —
moda searchwraps this endpoint with the same modes.