Documentation menu
Metadata filter syntax

Every chunk carries a metadata object. Any field you write — plus the system fields Anansi writes automatically — can be filtered at query time.

Filters are accepted on:

  • GET /v1/context — the filters query param, JSON-encoded
  • POST /v1/search — the filters body field
  • GET /v1/memories — the sourceType convenience param is a shorthand for a filter

Filter object shape

typescript
"kw">interface MetadataFilter { metadata?: Record<"kw">string, FilterValue>; $and?: MetadataFilter[]; $or?: MetadataFilter[]; } "kw">type FilterValue = | "kw">string | "kw">number | "kw">boolean | null "kw">class="cm">// equality / null check | { $gte?: "kw">number; $lte?: "kw">number; "kw">class="cm">// numeric range $gt?: "kw">number; $lt?: "kw">number; $contains?: unknown }; "kw">class="cm">// JSONB contains

Equality filters

Match chunks where a metadata field equals an exact value.

json
{ "metadata": { "sourceType": "conversation" } }
json
{ "metadata": { "author": "alice@example.com" } }

Null check:

json
{ "metadata": { "sessionId": null } }

Numeric range filters

json
{ "metadata": { "score": { "$gte": 0.8 } } }
json
{ "metadata": { "wordCount": { "$gt": 100, "$lte": 500 } } }

The field is cast to float before comparison, so it works for integers and decimals stored as JSON numbers.

Contains filter

Tests whether the metadata field's JSONB value contains the given value. Useful for arrays and nested objects.

json
{ "metadata": { "tags": { "$contains": "important" } } }
json
{ "metadata": { "labels": { "$contains": ["billing", "urgent"] } } }

Logical operators

Combine conditions with $and or $or at any level.

json
{ "$and": [ { "metadata": { "sourceType": "conversation" } }, { "metadata": { "score": { "$gte": 0.7 } } } ] }
json
{ "$or": [ { "metadata": { "sourceType": "meeting" } }, { "metadata": { "sourceType": "voice" } } ] }

Filters nest up to 5 levels deep and accept up to 50 total conditions. Multiple keys inside one metadata object are ANDed:

json
{ "metadata": { "sourceType": "conversation", "author": "alice@example.com" } }

System metadata fields

Anansi writes these fields on every chunk automatically. You can filter on any of them.

FieldTypeDescription
sourceTypestringThe sourceType you passed on ingest (conversation, meeting, etc.)
authorstringThe userId of the ingest caller, or overridden by metadata.author
authorIdstringAlways the userId of the ingest caller
timestampstringISO 8601 — metadata.timestamp if provided, otherwise ingest time
channelNamestringAlways "api" for API ingests
sessionIdstringOnly present if sessionId was provided on ingest
agentIdstringOnly present if agentId was provided on ingest
embedding_sourcestring"custom" when a bring-your-own embedding was used

Usage examples

GET /v1/context — filter relevant chunks by source type

shell
"kw">curl "https://anansimemory.com/v1/context?userId=user_123&q=what+stack&filters=%7B%22metadata%22%3A%7B%22sourceType%22%3A%22conversation%22%7D%7D" \ -H "Authorization: Bearer ans_..."

Or with a library:

typescript
"kw">const ctx = "kw">await memory.context({ userId: 'user_123', q: 'what stack does the user prefer?', filters: { metadata: { sourceType: 'conversation' } }, });

POST /v1/search — search within a date range

Assuming you store a numeric timestamp in metadata.timestamp on ingest:

json
{ "userId": "user_123", "query": "webhook issues", "filters": { "metadata": { "timestamp": { "$gte": 1717200000, "$lte": 1717286400 } } } }

Combining source type and recency

json
{ "$and": [ { "metadata": { "sourceType": "meeting" } }, { "metadata": { "score": { "$gte": 0.5 } } } ] }
Note
On the hosted service, metadata filters are a Pro+ feature. Filter values are compiled to parameterized SQL — never string-interpolated.