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.
Read & visualize: /api/agents/{agent_id}/players/{player_id}/memories
Manual edits (create / update / delete one): /api/v1/agents/{agent_id}/players/{player_id}/memories
:::info agent_id = character_id
The agent_id in the URL path is the same id returned by the Characters API.
:::
For background on how memory works, see Memory System.
List Memories
GET /api/agents/{agent_id}/players/{player_id}/memories
Returns a paginated list of memories.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
memory_type | string | -- | Filter by type: "fact", "preference", "relationship", "event", "emotional_state", "correction", "character_self", "spatial_change" |
status | string | "active" | Memory status: "active", "superseded", "decayed", or "deleted" |
limit | integer | 50 | Results per page (1-200) |
offset | integer | 0 | Number of results to skip |
sort_by | string | "created_at" | Sort field: "created_at", "confidence", "last_accessed_at" |
sort_order | string | "desc" | "asc" or "desc" |
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
| Field | Type | Description |
|---|---|---|
id | string | Unique memory identifier (UUID) |
userId | string | ID of the developer account that owns the memory |
agentId | string | Character (agent) ID this memory belongs to |
playerId | string | Player ID this memory was extracted for |
memoryType | string | One of: fact, preference, relationship, event, emotional_state, correction, character_self, spatial_change |
content | string | The memory content text |
confidence | number | Confidence score (0.0-1.0) |
status | string | "active", "superseded", "decayed", or "deleted" |
source | string | Origin of the memory: "text_chat" (auto-extracted from a conversation) or "manual_dashboard" (created via the Create Memory endpoint) |
memoryLayer | string | "ltm" (long-term) or "stm" (short-term). Controls how the memory ages -- short-term memories fade faster if unused |
importance | number | Importance weight (0.0-1.0) used during retrieval ranking |
sourceConversationId | string | null | Conversation that produced this memory. null for manually created memories |
sourceQuote | string | null | Original conversation text that produced this memory. null for manually created memories |
accessCount | number | How many times this memory has been retrieved |
createdAt | string | ISO 8601 creation timestamp |
lastAccessedAt | string | null | ISO 8601 timestamp of last retrieval |
extractedAt | string | null | ISO 8601 timestamp of extraction |
sourceMessageTimestamp | string | null | ISO 8601 timestamp of the source message |
updatedAt | string | null | ISO 8601 last update timestamp |
Examples
# All memories
curl "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories" \
-H "X-API-Key: est_your_api_key"
# Only fact memories, sorted by confidence
curl "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories?memory_type=fact&sort_by=confidence" \
-H "X-API-Key: est_your_api_key"
const res = await fetch(
`https://api.estuary-ai.com/api/agents/${agentId}/players/${playerId}/memories?memory_type=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/agents/{agent_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.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
content | string | Yes | -- | Memory text. 1-2000 characters |
memoryType | string | Yes | -- | One of: "fact", "preference", "relationship", "event", "emotional_state", "correction", "character_self", "spatial_change" |
importance | number | No | 0.5 | 0.0-1.0. Higher values are surfaced more aggressively during retrieval |
memoryLayer | string | No | "stm" | "ltm" for memories you want preserved long-term; "stm" for ephemeral ones |
confidence | number | No | 1.0 | 0.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/agents/{agent_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/agents/${agentId}/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/agents/{agent_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:
| Field | Type | Description |
|---|---|---|
content | string | New memory text (1-2000 chars) |
memoryType | string | New type |
importance | number | New importance (0.0-1.0) |
memoryLayer | string | "ltm" or "stm" |
confidence | number | New 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 agent/player. Counts toward the daily manual-write quota.
Example
curl -X PATCH "https://api.estuary-ai.com/api/v1/agents/{agent_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/agents/{agent_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
| Parameter | Type | Default | Description |
|---|---|---|---|
hard | boolean | false | If 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 agent/player.
Example
# Soft delete (recoverable)
curl -X DELETE "https://api.estuary-ai.com/api/v1/agents/{agent_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/agents/{agent_id}/players/player_xyz/memories/{memory_id}?hard=true" \
-H "X-API-Key: est_your_api_key"
Memory Timeline
GET /api/agents/{agent_id}/players/{player_id}/memories/timeline
Returns memories grouped by date for timeline visualization.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
group_by | string | "day" | Grouping period: "day", "week", "month" |
start_date | datetime | -- | Filter memories after this date (ISO 8601) |
end_date | datetime | -- | 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"
}
Example
curl "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories/timeline?group_by=week" \
-H "X-API-Key: est_your_api_key"
Memory Stats
GET /api/agents/{agent_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
}
| Field | Type | Description |
|---|---|---|
totalActive | number | Active memories |
totalSuperseded | number | Memories replaced by newer information |
totalDecayed | number | Memories that have decayed below threshold |
byType | object | Breakdown of active memories by type |
coreFacts | number | Number of core facts |
Example
curl "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories/stats" \
-H "X-API-Key: est_your_api_key"
Core Facts
GET /api/agents/{agent_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/agents/{agent_id}/players/player_xyz/memories/core-facts" \
-H "X-API-Key: est_your_api_key"
Knowledge Graph
GET /api/agents/{agent_id}/players/{player_id}/memories/graph
Returns the memory knowledge graph: clustered memories, entities, and their relationships.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
include_entities | boolean | false | Include entity nodes and relationship edges |
include_character_memories | boolean | false | Include 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
}
The stale flag indicates whether the response was served from a cache that is currently being refreshed in the background. When true, a fresh version is being computed and a subsequent request shortly after should return it.
Node types
| Type | Description |
|---|---|
user | The player node (center of the graph) |
cluster | A topic group containing related memories |
memory | An individual memory |
entity | A person, place, or thing mentioned in memories |
Edge types
| Type | Description |
|---|---|
has_cluster | User -> Cluster |
contains | Cluster -> Memory |
mentions | Memory -> Entity |
relationship | Entity -> Entity (with relationshipType and label) |
Example
curl "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories/graph?include_entities=true" \
-H "X-API-Key: est_your_api_key"
Search Memories
POST /api/agents/{agent_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.
Request Body
JSON, Content-Type: application/json.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes | -- | Search query (1-500 chars) |
limit | integer | No | 10 | Max results (clamped to 1-50) |
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
}
| Field | Type | Description |
|---|---|---|
memoryId | string | ID of the matching memory. Pass to the List Memories endpoint (or filter the response) to get the full memory object |
similarity | number | Vector similarity score (higher = more relevant) |
content | string | The matching memory's content text, included for convenience |
Example
curl -X POST "https://api.estuary-ai.com/api/agents/{agent_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/agents/${agentId}/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/agents/{agent_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.
The confirm=true query parameter is required. Requests without it return 400 Bad Request. This action cannot be undone.
Response
{
"message": "Deleted 87 records",
"deletedCount": 87
}
Example
curl -X DELETE "https://api.estuary-ai.com/api/agents/{agent_id}/players/player_xyz/memories?confirm=true" \
-H "X-API-Key: est_your_api_key"