twin memory

Search

Ask one end user's memory a question in plain words, and get back what is known, the dated facts behind it, and the passages they came from.

POST /v1/memory/searchAuth: read keyCost: one model call to keep only what the question needs

Search runs two lanes, word match and meaning, over one end user's memory, then keeps what the question needs. With no scope and no after, the answer is a brief: what is known now, the facts read from the conversation, and the passages. With either one, it is a ranked list of passages and facts inside that window. See Search.

Headers

Authorizationstringrequired

Bearer tm_…. A read key is enough.

X-Twin-Accountstringrequired

The end user whose memory to search. Letters, digits, ., _ and -, starting with a letter or digit. Up to 64 characters minus your organisation and project prefix; see End users.

X-Request-Idstring

Your id for this request, echoed on the response. One is minted when absent.

Body

querystringrequired

The question, in plain words. 1 to 2,000 characters.

beforedate

Only memory from before this day, as YYYY-MM-DD or a full ISO time. Alone, it still returns the brief, and the question is answered as of that day: nothing said after it is used.

afterdate

Only memory from this day on. Returns the ranked list rather than the brief.

scopestring

A path prefix to search under, such as passages/memory/messages. Up to 512 characters. Returns the ranked list.

fastboolean

Skip the model filter: the ranking comes back unfiltered, free and without waiting on a model, a little less precise. For a reply that can't wait, such as a voice agent's turn. Default false. Not offered to models over MCP.

A k field is ignored: the filter decides how many passages the question needs.

Response

querystring

The question as asked.

foundinteger

How many passages came back in hits.

knownstring[]

What is true now, one line per subject and attribute, with every value as stated and the day it was said, newest first. Brief only, once the conversation has been read.

factsobject[]

Dated facts read from the conversation. Each has id, text, thread, path and source, the address of the passage it was read from. Present once the conversation has been read.

hitsobject[]

The passages themselves, up to 1,400 characters each, with id, path and thread. Each also carries content: "stored" and roles, who spoke in it (user, assistant), so you can quote it as data; see Using memory with an LLM.

worked_outstring[]

Lines computed over the facts, such as a count or a conflict between two statements. Brief only, when the question asks for one.

notesstring[]

How to read the facts, for the model, such as which statements were the assistant's suggestions rather than the user's words. Brief only.

heldboolean

Whether the filter judged that the memory holds an answer. Brief only. Absent when filtering is off, with fast, or when your organisation is over its daily budget and search answers with the unfiltered ranking.

filteredboolean

Whether the model filter judged what came back. false with fast, past your organisation's daily budget, or when the filter could not be reached.

Errors

400bad request

X-Twin-Account is missing or not a usable id.

401unauthorized

The bearer is not a key this service issued.

404not found

no memory for end user 'user_42' yet. Nothing was ever written for this end user. Treat it as an empty memory.

413too large

body over 1000000 bytes.

422invalid

A field is out of bounds, such as an empty query or a date that is not a real day.

503unavailable

The service is at capacity, or this end user is being rebuilt. Retry after Retry-After seconds.

Request
curl https://api.twinmemory.dev/v1/memory/search \
  -H "Authorization: Bearer $TWIN_MEMORY_API_KEY" \
  -H "X-Twin-Account: user_42" \
  -H "Content-Type: application/json" \
  -d '{ "query": "Where does Alice live?" }'
200 OK
{
  "query": "Where does Alice live?",
  "found": 1,
  "known": [
    "Values as stated, newest said first:",
    "- Alice Chen · home_city: Lisbon [said 2026-10-01]; Berlin [said 2024-06-01]"
  ],
  "facts": [
    {
      "path": "records/th_8b5e5d4c8946d815.json#1",
      "id": "th_8b5e5d4c8946d815#r028d461216652fe5",
      "thread": "th_8b5e5d4c8946d815",
      "source": "passages/memory/messages/th_8b5e5d4c8946d815/p_0001.md",
      "text": "(happened 2026-10-01) Alice lives in Lisbon (Alice · home_city: Lisbon) (state)"
    }
  ],
  "hits": [
    {
      "path": "passages/memory/messages/th_8b5e5d4c8946d815/p_0001.md",
      "id": "th_8b5e5d4c8946d815/p_0001",
      "thread": "th_8b5e5d4c8946d815",
      "text": "Context: messages (memory), 1 Oct 2026. … **Alice Chen** 09:30 · I just moved to Lisbon…"
    }
  ],
  "held": true,
  "filtered": true
}
200 OK, scoped to passages/memory after 2026-10-01
{
  "query": "Porto",
  "found": 1,
  "hits": [
    {
      "path": "passages/memory/documents/th_a4c4bfb9e995f6bc/p_0001.md",
      "id": "th_a4c4bfb9e995f6bc/p_0001",
      "thread": "th_a4c4bfb9e995f6bc",
      "text": "Context: documents (memory), 3 Oct 2026. Porto trip plan.\n\nDay 1: train from Lisbon to Porto at 08:00. …"
    }
  ]
}