Search
POST /api/v1/search — the same hybrid vector + keyword + entity ranking as Recall, returned as ranked memories without the LLM-written summary.
POST /api/v1/search and POST /api/v1/recall take the same request body and rank memories the same way. Search returns the ranked memories as items and stops there. Recall runs the same search and then asks a model to write a summary of the results, which adds seconds per call. Use search when your code, or an SDK such as Rail, builds its own prompt from the memories; use recall when you want the synthesized brief.
Set caller_agent_id to the agent the search runs as. It decides which agent-private memories are visible and whose trust and fleet the read is gated against, without filtering results to that agent's own memories. Available since open-source release backend-v2.47.0.
APIKeyHeaderX-API-Key<token>application/json- body
tenant_id?Tenant IdTenant to operate on. Omit it and the tenant is resolved from the credential, which is what a tenant- or agent-scoped key already identifies — no prior /whoami call is needed. Supply it to act on a different tenant your credential may read (and for an admin key, which belongs to no single tenant, it is required).
""fleet_ids?array<string>|nullquery*Query1 <= length <= 5000filter_agent_id?string|nullcaller_agent_id?|Assert the agent identity this search runs as, WITHOUT filtering results to that agent's own memories (use filter_agent_id for that). Determines which scope_agent memories are visible and whose trust/fleet level the read is gated against. Ignored when the credential already carries an agent identity, which wins. An agent-scoped credential may only name itself.
memory_type_filter?|Filter results to a single memory type. Valid values: fact, episode, decision, preference, task, semantic, intention, plan, commitment, action, outcome, cancellation, rule, insight.
status_filter?|Restrict results to one status. When omitted, superseded memories are hidden: 'outdated' rows are excluded, and 'conflicted' rows are excluded unless they exactly match the query text. Their replacements are injected in their place. Pass an explicit status to bypass this and read the superseded rows directly.
valid_at?|As-of time for the question (ISO 8601). Rows whose ts_valid_start is after this date are excluded and rows whose ts_valid_end is before it are down-weighted; relative dates in the query ('last month') are resolved against it. When the tenant's search.default_profile sets freshness_reference=1, freshness and the temporal window are ALSO measured from this time against each row's event time (ts_valid_start, else created_at) instead of from now() — the setting for backfilled corpora where ingest time carries no signal. Naive values are read as UTC.
top_k?Top KMaximum results the query returns (1-200, default 5). Not the response ceiling: each returned outdated/conflicted row also carries its newest correction, injected beyond this budget and marked injected: true (with score: null), so a response holds at most 2*top_k items. Also accepted as 'limit': sent on its own it is absorbed silently and no warning is raised. Sent together with 'top_k', top_k wins and the response carries a 'superseded_parameter_alias' warning naming 'limit' as superseded by 'top_k' — not an 'unrecognized_parameters' one, because the endpoint does read 'limit'; it was simply outranked.
1 <= value <= 2005min_similarity?|Per-request similarity floor (0.0-1.0) applied to the raw cosine; overrides the agent/tenant search-profile value for this call.
diagnostic?Diagnosticfalseinclude_derived?|Whether to return atomic-fact fan-out children — short single-claim rows the platform derives from a memory you wrote, which stay retrievable alongside it. Omit to inherit the tenant's search.include_derived setting, which in turn falls back to the global default (currently true). Precedence: this field beats the tenant setting beats the global default. Excluded rows are dropped BEFORE the top_k trim, so top_k still returns top_k rows. Does not affect auto-chunk children, which are the only sub-document vectors a long document has. REST only: the MCP tools do not expose this per request — an MCP caller sets the tenant's search.include_derived instead, and an unknown argument sent to an MCP tool is dropped silently rather than reported (oss-0923-h-01).
recall_boost?|Set false for this call only to neutralise the popularity recall_boost factor (score multiplier fixed at 1.0) AND to skip the recall_count bump for the returned rows, so the read neither uses nor feeds the recall signal (the response reports recall_tracked: false). Omit (or true) for the tenant's behaviour; a request cannot enable the boost over a tenant that disabled it. REST only: the MCP tools do not expose this per request.
entity_boost?|Set false for this call only to rank by the plain hybrid (vector + full-text) score: entity/graph retrieval is skipped, so no entity boost multiplier is applied and the ENTITY_LOOKUP short-circuit cannot fire. Omit (or true) for the tenant's search.entity_retrieval behaviour; a request cannot enable entity retrieval over a tenant that disabled it. REST only: the MCP tools do not expose this per request.
[key: string]?anySuccessful Response
application/json- response
Envelope for search results — matches PaginatedMemoryResponse shape.
items*array<>recall_tracked?Recall TrackedWhether this search bumped recall_count for the memories it returned. False means they were not reinforced: the caller presented no agent identity (a tenant-scoped key that did not set filter_agent_id — recall_count stays 0 for that caller and recall_boost never engages), the call set diagnostic=true or recall_boost=false, or nothing matched.
falsediagnostic?|nullwarnings?array<>|nullcurl -X POST 'https://example.com/api/v1/search' \ -H 'Content-Type: application/json' \ -d '{ "query": "string"}'{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "tenant_id": "string", "fleet_id": "string", "agent_id": "string", "agent_display_name": "string", "memory_type": "string", "title": "string", "content": "string", "weight": 0, "source_uri": "string", "run_id": "string", "metadata": {}, "system_metadata": {}, "created_at": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z", "entity_links": [], "similarity": 0, "score": 0, "score_parts": { "vec_sim": 0, "fts_score": 0, "freshness": 0, "entity_boost": 0, "recall_boost": 0, "temporal_boost": 0, "status_penalty": 0, "rerank": 0 }, "injected": false, "subject_entity_id": "2f43e1a1-7cec-4ccf-9421-4ab19090ca45", "predicate": "string", "object_value": "string", "ts_valid_start": "2019-08-24T14:15:22Z", "ts_valid_end": "2019-08-24T14:15:22Z", "status": "active", "visibility": "scope_team", "recall_count": 0, "last_recalled_at": "2019-08-24T14:15:22Z", "supersedes_id": "8149cd94-4e90-4a99-91f5-a3e0f9b829dc", "superseded_by": [ { "old_memory_id": "07606bd2-b9bc-468a-8200-790e8b7345cf", "old_status": "string", "reason": "string", "old_content_preview": "string", "direction": "canonical" } ], "confidence": 0, "is_inferred": false, "scope": {}, "usage": { "memories_stored": 0, "memories_limit": 0, "writes_remaining": 0 } } ], "recall_tracked": false, "diagnostic": { "retrieval_strategy": "string", "top_k_requested": 0, "min_similarity_applied": 0, "candidates_considered": 0, "returned": 0, "excluded_below_min_similarity": 0, "excluded_by_top_k_trim": 0, "search_params": {}, "all_candidates": [], "entity_matches": 0, "entity_match_declined": false }, "warnings": [ { "code": "string", "message": "string", "details": {} } ]}