Memory API
Endpoint reference
Four endpoints today, and what is coming. Every field below is the wire name.
POST/ingest
Push one unit of content. Runs the full pipeline and queues per tenant, so content applies in the order it is sent.
| Field | Description |
|---|---|
contentstringrequired | The raw text. No shape is imposed. |
labelstring | Human-readable descriptor for the kind of content. Defaults to "Ingested data point". |
idstring | Stable identifier for this source. Re-sending the same id replaces the stored point. Omit and one is generated. |
timestampISO 8601 | When the content happened, not when it was sent. Backdatable. Defaults to now. |
metadataobject | Arbitrary JSON stored alongside the point and never interpreted. |
appendboolean | Splice content onto the stored point instead of replacing it, for a growing log or a continuing conversation. Only the new tail is re-embedded. |
groupstring | Free-form grouping key, max 200 characters. Points sharing a group are distilled into one dated record. |
teamIdinteger | Required only when the token reaches more than one workspace. |
audiencestring or arraycoming soon | Scope this data point to particular end users instead of the whole workspace. See the roadmap for the date. |
202 Accepted
{
"teamId": 8837,
"ingestionId": "b41c9e2a7f6d4c118a3e",
"sourceId": "call-8821",
"status": "queued"
}GET/ingest/{ingestionId}
Poll until the queue has applied the content and finished its deferred maintenance. Pass teamId as a query parameter if the token reaches more than one workspace.
200 OK
{
"teamId": 8837,
"ingestionId": "b41c9e2a7f6d4c118a3e",
"status": "completed",
"settled": true,
"blocked": false,
"readiness": {
"raw": 1.0,
"comprehension": 1.0,
"consolidation": 1.0,
"parked": 0
}
}- Gate on
settled, not onstatus.settledis true only when every stage has drained with nothing parked.statuscan read"completed"while distillation is still outstanding, and reading then returns a half-written graph. blocked: truemeans every remaining row parked. Stop polling and inspect the feed rather than waiting out the timeout.readinessis a live progress vector, enough to show a real progress bar instead of a spinner.- The queue is FIFO, so the last ingestion id of a feed covers the whole feed. There is no need to poll every id.
POST/recall
Returns ranked evidence with its sources and no generated text, for running a separate model over the context.
| Field | Description |
|---|---|
querystringrequired | A natural-language question. Retrieval plans its own traversals from it. |
maxTokensinteger | A token budget for the returned evidence rather than a result count. Evidence is included most-relevant-first until the budget is spent. Minimum 256. Omit for everything. |
limitinteger | Cap on evidence matches returned. |
queryTimestampISO 8601 | Anchors relative-time reasoning ("last week") to a point in the past. Use it when replaying a historical conversation. |
includeTimelineboolean | Include the complete dated record for the subject, not only the top matches. |
verbatimboolean | Return raw source excerpts instead of the distilled form. Ordering questions need this, because only the raw corpus preserves within-source order. |
tagstring | Free-form correlation tag, echoed into usage records. |
teamIdinteger | Required only when the token reaches more than one workspace. |
200 OK
{
"teamId": 8837,
"results": [ /* typed matches, each with its source and score */ ],
"evidence": [
"Nadia confirmed the pilot ships March 14 (Account review call, 2026-02-03)",
"Budget for the Acme pilot moved to 40k (Email from Nadia, 2026-07-28)"
],
"truncated": false,
"timelineIsVerbatim": false,
"intent": "Lookup",
"degradedArms": [],
"usage": {
"recallTokensIn": 812,
"recallTokensOut": 96,
"recallCostUsd": 0.000214
}
}degradedArmsnames any retrieval arm that stayed degraded after its retry, which tells a partial search apart from a complete one that found little. An empty array means every arm ran.truncatedmeans the token budget cut the result set. Bothresultsandevidenceare cut identically.
POST/answer
Recall plus a grounded answer. Takes every /recall field, plus the three below.
| Field | Description |
|---|---|
querystringrequired | The question to answer. |
modepipeline | agent | pipeline (default) is one shot: retrieve, then answer. agent runs a loop that can refine its own retrieval before committing, at higher latency and cost. |
responseSchemaJSON Schema | Force a structured answer. Supported in pipeline mode only; sending it with mode: "agent" is rejected rather than silently ignored. |
budgetstring | Named context budget for the answerer. |
200 OK
{
"teamId": 8837,
"answer": "March 14, 2026. Nadia confirmed it on the February 3 account review call.",
"evidence": [
"Nadia confirmed the pilot ships March 14 (Account review call, 2026-02-03)"
],
"abstained": false,
"answerer": "gemini-3.5-flash",
"intent": "Lookup",
"recordKept": 12,
"recordTotal": 12,
"degradedArms": [],
"usage": {
"answerTokensIn": 2140,
"answerTokensOut": 38,
"answerCachedTokensIn": 1792,
"answerCostUsd": 0.000431,
"recallTokensIn": 812,
"recallTokensOut": 96,
"recallCostUsd": 0.000214
}
}abstained: truemeans the memory did not hold the answer, so the model declined to generate one. Handle it as a normal outcome.recordKeptandrecordTotalseparate "the record never loaded" from "the record loaded and the answer still missed": a retrieval problem versus a reasoning one.- In
agentmode the response carriestoolCallsinstead ofevidence, listing the retrieval steps the loop took.
Entities, relationships and hops
| Route | What it will do |
|---|---|
GET/entities | Search entities by text and type. The list view over the graph, for populating a UI rather than answering a question. |
POST/entities | Create an entity directly, instead of waiting for extraction to derive it from content. |
GET/entities/{id} | One entity with its three layers: the mentions it was built from, the dated observations drawn out of them, and the value that holds now. |
PATCH/entities/{id} | Correct or set values on an entity without re-ingesting the content it came from. |
DELETE/entities/{id} | Remove an entity along with the facts derived from it. |
GET/entities/{id}/memories | The memories behind one entity: verbatim mentions with their sources and timestamps, and the observations drawn from them. |
GET/entities/{id}/relationships | The typed relationships into and out of an entity, with the dates they hold for. |
GET/entities/{id}/hops | Traverse outward to a given depth, for walking a neighbourhood of the graph rather than querying it. |