Skip to main content

Memories API

Query and manage a character's memory of a specific player. Estuary automatically builds memory from conversations -- this API lets you read what the character remembers, search across it, visualize it as a knowledge graph, and edit it manually.

Base path: /api/v1/characters/{character_id}/players/{player_id}/memories

:::info character_id The character_id in the URL path is the id returned by the Characters API. :::

Query parameter names are camelCase, and unknown query parameters are ignored, so a snake_case name silently has no effect.

:::note Legacy routes The bare /api/agents/... memory routes and the /api/v1/agents/... memory write routes still work, but they are deprecated. Responses from them carry Deprecation and Link headers, plus a Sunset header once a removal date is set. See the legacy migration guide for the full mapping. :::

For background on how memory works, see Memory System.


List Memories​

GET /api/v1/characters/{character_id}/players/{player_id}/memories

Returns a paginated list of memories, newest first.

Query Parameters​

ParameterTypeDefaultDescription
memoryTypestring--Filter by type: "fact", "preference", "relationship", "event", "emotional_state", "correction", "character_self", "spatial_change"
statusstring"active"Memory status: "active", "superseded", "decayed", "deleted", or "quarantined"
limitinteger50Results per page (1-200)
offsetinteger0Number of results to skip (minimum 0)

Results are returned newest first. This endpoint does not accept sort parameters.

Response​

{
"memories": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user_def456",
"agentId": "550e8400-e29b-41d4-a716-446655440001",
"playerId": "player_xyz",
"memoryType": "fact",
"content": "The user works as a software engineer at a startup in San Francisco",
"confidence": 0.92,
"status": "active",
"source": "text_chat",
"memoryLayer": "ltm",
"importance": 0.78,
"sourceConversationId": "conv_def456",
"sourceQuote": "I work as a software engineer at this startup in SF",
"accessCount": 3,
"createdAt": "2026-02-10T15:30:00",
"lastAccessedAt": "2026-03-01T14:22:00",
"extractedAt": "2026-02-10T15:31:00",
"sourceMessageTimestamp": "2026-02-10T15:29:50",
"updatedAt": "2026-02-10T15:30:00"
}
],
"total": 87,
"limit": 50,
"offset": 0
}

Memory Object Fields​

FieldTypeDescription
idstringUnique memory identifier (UUID)
userIdstringID of the developer account that owns the memory
agentIdstringThe character this memory belongs to. The field keeps its older name, but the value is the same character_id used in the URL path
playerIdstringPlayer ID this memory was extracted for
memoryTypestringOne of: fact, preference, relationship, event, emotional_state, correction, character_self, spatial_change
contentstringThe memory content text
confidencenumberConfidence score (0.0-1.0)
statusstring"active", "superseded", "decayed", "deleted", or "quarantined"
sourcestringOrigin of the memory: "text_chat" (auto-extracted from a conversation) or "manual_dashboard" (created via the Create Memory endpoint)
memoryLayerstring"ltm" (long-term) or "stm" (short-term). Controls how the memory ages -- short-term memories fade faster if unused
importancenumberImportance weight (0.0-1.0) used during retrieval ranking
sourceConversationIdstring | nullConversation that produced this memory. null for manually created memories
sourceQuotestring | nullOriginal conversation text that produced this memory. null for manually created memories
accessCountnumberHow many times this memory has been retrieved
createdAtstringISO 8601 creation timestamp
lastAccessedAtstring | nullISO 8601 timestamp of last retrieval
extractedAtstring | nullISO 8601 timestamp of extraction
sourceMessageTimestampstring | nullISO 8601 timestamp of the source message
updatedAtstring | nullISO 8601 last update timestamp

id, agentId, playerId, content, source, importance and memoryLayer are always present. Every other field may be null.

Examples​

# All memories
curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories" \
-H "X-API-Key: est_your_api_key"

# Only fact memories
curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories?memoryType=fact" \
-H "X-API-Key: est_your_api_key"
const res = await fetch(
`https://api.estuary-ai.com/api/v1/characters/${characterId}/players/${playerId}/memories?memoryType=event&limit=20`,
{ headers: { "X-API-Key": "est_your_api_key" } }
);
const data = await res.json();
console.log(`${data.total} event memories`);

Create Memory​

POST /api/v1/characters/{character_id}/players/{player_id}/memories

Create a memory manually -- useful for seeding context, importing data, or building a dashboard that lets end users teach the character.

Request Body​

JSON, Content-Type: application/json. All keys are camelCase.

FieldTypeRequiredDefaultDescription
contentstringYes--Memory text. 1-2000 characters
memoryTypestringYes--One of: "fact", "preference", "relationship", "event", "emotional_state", "correction", "character_self", "spatial_change"
importancenumberNo0.50.0-1.0. Higher values are surfaced more aggressively during retrieval
memoryLayerstringNo"stm""ltm" for memories you want preserved long-term; "stm" for ephemeral ones
confidencenumberNo1.00.0-1.0. Defaults to 1.0 because manual entries are presumed accurate

Unknown fields are rejected with 422 Unprocessable Entity.

Response​

201 Created with the full Memory object. The created memory has source: "manual_dashboard" and sourceConversationId: null.

Quotas​

Manual writes (create + update combined) are limited to 1,000 per day per developer account. Exceeding the cap returns 429 Too Many Requests:

{ "detail": "Manual memory write quota exceeded (1000/day)" }

The counter resets at UTC midnight.

Example​

curl -X POST "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories" \
-H "X-API-Key: est_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"content": "The user is allergic to peanuts.",
"memoryType": "fact",
"importance": 0.9,
"memoryLayer": "ltm"
}'
const res = await fetch(
`https://api.estuary-ai.com/api/v1/characters/${characterId}/players/${playerId}/memories`,
{
method: "POST",
headers: {
"X-API-Key": "est_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "The user is allergic to peanuts.",
memoryType: "fact",
importance: 0.9,
memoryLayer: "ltm",
}),
}
);
const memory = await res.json();
console.log("Created", memory.id);

Update Memory​

PATCH /api/v1/characters/{character_id}/players/{player_id}/memories/{memory_id}

Partially update a memory. Send only the fields you want to change. Omitted fields are left untouched.

Request Body​

Same field set as Create Memory -- all fields optional:

FieldTypeDescription
contentstringNew memory text (1-2000 chars)
memoryTypestringNew type
importancenumberNew importance (0.0-1.0)
memoryLayerstring"ltm" or "stm"
confidencenumberNew confidence (0.0-1.0)

Unknown fields return 422. A body with no recognized fields is a no-op and returns the existing memory unchanged.

Response​

200 OK with the updated Memory object.

Returns 404 Not Found if the memory doesn't exist or belongs to a different character or player. Counts toward the daily manual-write quota.

Example​

curl -X PATCH "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/{memory_id}" \
-H "X-API-Key: est_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "content": "The user is allergic to peanuts and tree nuts.", "importance": 0.95 }'

Delete a Memory​

DELETE /api/v1/characters/{character_id}/players/{player_id}/memories/{memory_id}

Delete a single memory. By default this is a soft delete -- the memory's status flips to "deleted" and it is excluded from retrieval, but the row is preserved so it can be inspected later. Pass ?hard=true to remove the row entirely.

Query Parameters​

ParameterTypeDefaultDescription
hardbooleanfalseIf true, permanently removes the memory. If false, marks it deleted but preserves the row

Response​

204 No Content on success. Empty body.

Returns 404 Not Found if the memory doesn't exist or belongs to a different character or player.

Example​

# Soft delete (recoverable)
curl -X DELETE "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/{memory_id}" \
-H "X-API-Key: est_your_api_key"

# Hard delete (permanent)
curl -X DELETE "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/{memory_id}?hard=true" \
-H "X-API-Key: est_your_api_key"

Memory Timeline​

GET /api/v1/characters/{character_id}/players/{player_id}/memories/timeline

Returns memories grouped by date for timeline visualization. The timeline covers the 500 most recent active memories.

Query Parameters​

ParameterTypeDefaultDescription
groupBystring"day"Grouping period: "day", "week", "month"
startDatedatetime--Filter memories after this date (ISO 8601)
endDatedatetime--Filter memories before this date (ISO 8601)

Response​

{
"timeline": [
{
"date": "2026-03-01",
"memories": [ /* Memory objects */ ]
},
{
"date": "2026-02-28",
"memories": [ /* Memory objects */ ]
}
],
"totalMemories": 87,
"groupBy": "day"
}

Each date is YYYY-MM-DD (the day itself for "day" grouping, the Monday of the week for "week") or YYYY-MM for "month" grouping.

Example​

curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/timeline?groupBy=week" \
-H "X-API-Key: est_your_api_key"

Memory Stats​

GET /api/v1/characters/{character_id}/players/{player_id}/memories/stats

Returns aggregate statistics about a player's memory.

Response​

{
"totalActive": 87,
"totalSuperseded": 5,
"totalDecayed": 3,
"byType": {
"fact": 32,
"preference": 15,
"relationship": 8,
"event": 18,
"emotional_state": 6,
"correction": 2,
"character_self": 4,
"spatial_change": 2
},
"coreFacts": 12,
"byLayer": {
"ltm": 61,
"stm": 26
},
"lastLayerTransferAt": "2026-03-01T04:00:00",
"recentPromotions7d": 4,
"recentDemotions7d": 1
}
FieldTypeDescription
totalActivenumberActive memories
totalSupersedednumberMemories replaced by newer information
totalDecayednumberMemories that have decayed below threshold
byTypeobjectBreakdown of active memories by type (type name to count)
coreFactsnumberNumber of core facts
byLayerobjectBreakdown of active memories by layer (layer name to count)
lastLayerTransferAtstring | nullISO 8601 timestamp of the most recent layer change, or null if none has happened
recentPromotions7dnumberMemories promoted from short-term to long-term in the last 7 days
recentDemotions7dnumberMemories demoted from long-term to short-term in the last 7 days

Example​

curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/stats" \
-H "X-API-Key: est_your_api_key"

Core Facts​

GET /api/v1/characters/{character_id}/players/{player_id}/memories/core-facts

Returns the core facts the character knows about a player. Core facts are concise, structured statements (name, location, interests, etc.) always included in the LLM context.

Response​

{
"coreFacts": [
{
"id": "fact_001",
"userId": "user_abc",
"agentId": "agent_xyz",
"playerId": "player_xyz",
"factKey": "name",
"factValue": "Alex",
"sourceMemoryId": "mem_abc123",
"createdAt": "2026-02-10T15:30:00",
"updatedAt": "2026-03-01T14:22:00"
},
{
"id": "fact_002",
"userId": "user_abc",
"agentId": "agent_xyz",
"playerId": "player_xyz",
"factKey": "occupation",
"factValue": "Software engineer at a startup",
"sourceMemoryId": "mem_def456",
"createdAt": "2026-02-12T10:00:00",
"updatedAt": null
}
]
}

Example​

curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/core-facts" \
-H "X-API-Key: est_your_api_key"

Knowledge Graph​

GET /api/v1/characters/{character_id}/players/{player_id}/memories/graph

Returns the memory knowledge graph: clustered memories, entities, and their relationships.

Query Parameters​

ParameterTypeDefaultDescription
includeEntitiesbooleanfalseInclude entity nodes and relationship edges
includeCharacterMemoriesbooleanfalseInclude the character's self-reflective memories

Response​

{
"nodes": [
{ "id": "user_player_xyz", "type": "user", "label": "player_xyz" },
{ "id": "cluster_0", "type": "cluster", "label": "Work & Career", "memoryCount": 12 },
{ "id": "mem_abc", "type": "memory", "label": "Works as a software engineer...", "memoryType": "fact" },
{ "id": "ent_001", "type": "entity", "entityType": "person", "name": "Alex" }
],
"edges": [
{ "source": "user_player_xyz", "target": "cluster_0", "type": "has_cluster" },
{ "source": "cluster_0", "target": "mem_abc", "type": "contains" },
{ "source": "mem_abc", "target": "ent_001", "type": "mentions" }
],
"stats": {
"totalMemories": 87,
"totalEntities": 15,
"clusterCount": 6,
"clusters": { "Work & Career": 12, "Hobbies": 8 }
},
"stale": false
}

stale is true when a cached graph was returned immediately while a fresh one is being computed. A request shortly afterwards should return the fresh version.

Node and edge objects are heterogeneous: the keys present depend on the node or edge type, and new keys may be added. Read the keys you need and tolerate the ones you don't recognize.

Node types​

TypeDescription
userThe player node (center of the graph)
clusterA topic group containing related memories
memoryAn individual memory
entityA person, place, or thing mentioned in memories

Edge types​

TypeDescription
has_clusterUser -> Cluster
containsCluster -> Memory
mentionsMemory -> Entity
relationshipEntity -> Entity (with relationshipType and label)

Example​

curl "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/graph?includeEntities=true" \
-H "X-API-Key: est_your_api_key"

Search Memories​

POST /api/v1/characters/{character_id}/players/{player_id}/memories/search

Semantic search across a player's memories using vector similarity. The query is embedded once and matched against both text-derived and image-derived memories; results are merged and ranked by similarity.

:::note Search is a read Despite the POST method, search is a read operation: an API key with only the memories:read scope can call it. The search text goes in the JSON body as query, not in a q query parameter, and a GET to this path returns 405 Method Not Allowed. :::

Request Body​

JSON, Content-Type: application/json.

FieldTypeRequiredDefaultDescription
querystringYes--Search query (1-500 chars)
limitintegerNo10Max results (1-50)

Unknown fields are rejected with 422 Unprocessable Entity.

Response​

{
"results": [
{
"memoryId": "550e8400-e29b-41d4-a716-446655440000",
"similarity": 0.87,
"content": "The user talked about hiking in Rocky Mountain National Park last summer"
}
],
"query": "hiking trips",
"total": 1
}
FieldTypeDescription
memoryIdstringID of the matching memory. Pass to the List Memories endpoint (or filter the response) to get the full memory object
similaritynumberVector similarity score (higher = more relevant)
contentstringThe matching memory's content text, included for convenience

Example​

curl -X POST "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories/search" \
-H "X-API-Key: est_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "query": "hiking trips", "limit": 5 }'
const res = await fetch(
`https://api.estuary-ai.com/api/v1/characters/${characterId}/players/${playerId}/memories/search`,
{
method: "POST",
headers: {
"X-API-Key": "est_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "favorite foods", limit: 10 }),
}
);
const data = await res.json();
data.results.forEach((r) => {
console.log(`[${r.similarity.toFixed(2)}] ${r.content}`);
});

Delete All Memories​

DELETE /api/v1/characters/{character_id}/players/{player_id}/memories?confirm=true

Permanently deletes all memories for a player-character pair. Useful for GDPR compliance and right-to-be-forgotten requests. To delete a single memory, use Delete a Memory instead.

warning

The confirm=true query parameter is required. Requests without it return 400 Bad Request. This action cannot be undone.

Response​

200 OK with the number of records removed:

{
"deletedCount": 87
}

Example​

curl -X DELETE "https://api.estuary-ai.com/api/v1/characters/{character_id}/players/player_xyz/memories?confirm=true" \
-H "X-API-Key: est_your_api_key"