Memory API
Read and manage your users' memories through the Platform API.
The Memory API exposes your organization's user memories as a single resource on api.elyxir.ai. You can list, add, update, delete, and incrementally sync memories for any member of your organization. All responses are formatted as flat MemoryItem objects — the internal architecture is intentionally not surfaced.
Rollout in progress: the Memory API authenticates with OAuth JWT bearer tokens. It is available today in sandbox and staging environments; production availability is rolling out.
Authentication
The Memory API uses the same Platform API authentication as the API Keys and Usage endpoints. Every request requires two credentials:
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <platform-credential> |
X-Organization-Id | Yes | Your organization UUID |
Content-Type | For POST/PATCH | Must be application/json |
The platform credential is the RS256 OAuth JWT issued by the Elyxir authorization server. The organization UUID is available from the OAuth userinfo endpoint.
All responses include Cache-Control: no-store.
The MemoryItem Object
Every response wraps memories as MemoryItem objects:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content": "Prefers concise answers with code examples",
"category": "preference",
"createdAt": "2026-07-18T10:00:00.000Z",
"updatedAt": "2026-07-18T10:00:00.000Z"
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique identifier for this memory |
content | string | The memory text |
category | string | One of the six category values below |
createdAt | string (ISO 8601) | When this memory was first recorded |
updatedAt | string (ISO 8601) | When this memory was last changed |
Category Values
| Value | Meaning |
|---|---|
identity | Who the user is — name, role, background |
preference | Stated preferences and working style |
goal | Things the user is working toward |
project | Project-specific context |
relationship | Connections to people, teams, or systems |
constraint | Hard limits or rules the user has stated |
If you POST a memory without a category, or with an unrecognized value, the category is omitted (the memory is still saved).
In rare cases a save is folded into an existing memory rather than creating a new one; the response is then 200 {"ok": true} (no memory object), or a minimal {"memory": {"id", "content"}}. Treat the absence of a full memory object as "saved, nothing new to store."
User Override
By default, every request operates on the memory of the user who owns the credential. To act on behalf of a different member of your organization, include a user query parameter (GET/PATCH/DELETE) or a user body field (POST) containing the target user's UUID. The target user must be a member of the organization identified by X-Organization-Id.
Project Memory
Projects have a shared memory pool: memories contributed in a project's context are visible to every project collaborator. To work with a project's pool instead of a user's memories, pass the project's UUID:
GET /api/v1/memory?project=<uuid>— list (or incrementally sync, withsince) the project's shared memories. Requires access to the project.POST /api/v1/memorywith aprojectfield — contribute a memory to the pool. Requires editor access to the project.
The project selector cannot be combined with the user override. Editing and deleting through /api/v1/memory/{id} always applies to memories you contributed yourself.
Endpoints
List Memories
GET https://api.elyxir.ai/api/v1/memory
Returns all active memories for the user. For incremental sync, pass a since cursor from a previous response.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
since | No | Cursor from a previous response. Returns only memories changed since that point, plus a deleted array of IDs to remove locally. |
user | No | UUID of an org member to act on behalf of (defaults to key owner) |
# Full pull
curl https://api.elyxir.ai/api/v1/memory \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000"
# Incremental pull
curl "https://api.elyxir.ai/api/v1/memory?since=2026-07-18T10%3A00%3A00.000Z" \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000"Full Response (no since)
{
"memories": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content": "Prefers concise answers with code examples",
"category": "preference",
"createdAt": "2026-07-18T10:00:00.000Z",
"updatedAt": "2026-07-18T10:00:00.000Z"
}
],
"cursor": "2026-07-18T10:00:00.000Z"
}Incremental Response (with since)
{
"memories": [
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"content": "Working on a TypeScript monorepo project",
"category": "project",
"createdAt": "2026-07-18T11:00:00.000Z",
"updatedAt": "2026-07-18T11:00:00.000Z"
}
],
"deleted": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"cursor": "2026-07-18T11:00:00.000Z"
}The deleted array contains IDs that were removed since the last sync and should be dropped from local storage. The deleted field is only present on incremental responses.
Get a Memory
GET https://api.elyxir.ai/api/v1/memory/{id}
Returns a single memory by ID.
curl https://api.elyxir.ai/api/v1/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000"{
"memory": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content": "Prefers concise answers with code examples",
"category": "preference",
"createdAt": "2026-07-18T10:00:00.000Z",
"updatedAt": "2026-07-18T10:00:00.000Z"
}
}Add a Memory
POST https://api.elyxir.ai/api/v1/memory
Adds a new memory. Returns the saved memory as a MemoryItem.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The memory text. Must be non-empty. |
category | string | No | One of the six category values. Omitted or unrecognized values are silently dropped. |
user | string (UUID) | No | Target user UUID (must be an org member) |
curl -X POST https://api.elyxir.ai/api/v1/memory \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000" \
-H "Content-Type: application/json" \
-d '{
"content": "Prefers TypeScript over JavaScript",
"category": "preference"
}'{
"memory": {
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"content": "Prefers TypeScript over JavaScript",
"category": "preference",
"createdAt": "2026-07-18T12:00:00.000Z",
"updatedAt": "2026-07-18T12:00:00.000Z"
}
}Update a Memory
PATCH https://api.elyxir.ai/api/v1/memory/{id}
Updates the content and/or category of a memory. At least one field must be provided.
Note: Optimistic-concurrency conflict detection (409 response with a
baseUpdatedAtfield) is shipping in a forthcoming release. When available, you can passbaseUpdatedAtmatching theupdatedAtof the memory you read, and a 409 will be returned if another writer changed the record since then.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | No | New content text (must be non-empty if provided) |
category | string | No | New category value |
curl -X PATCH https://api.elyxir.ai/api/v1/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000" \
-H "Content-Type: application/json" \
-d '{
"content": "Prefers concise TypeScript answers with working code examples"
}'{
"memory": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content": "Prefers concise TypeScript answers with working code examples",
"category": "preference",
"createdAt": "2026-07-18T10:00:00.000Z",
"updatedAt": "2026-07-18T12:30:00.000Z"
}
}Delete a Memory
DELETE https://api.elyxir.ai/api/v1/memory/{id}
Deletes a memory. The operation is idempotent — deleting an already-deleted ID returns {ok: true} without error. Deleted IDs appear in the deleted array of subsequent incremental pulls.
curl -X DELETE https://api.elyxir.ai/api/v1/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer <credential>" \
-H "X-Organization-Id: 00000000-0000-0000-0000-000000000000"{
"ok": true
}Incremental Sync
The cursor field returned by every GET is an opaque high-watermark string. Pass it back as ?since=<cursor> on your next request to receive only records that changed since that point.
Recommended sync loop:
- On first launch, call
GET /api/v1/memory(nosince). Store thecursorand all returnedmemorieslocally. - On subsequent syncs, call
GET /api/v1/memory?since=<stored-cursor>. - Upsert each item in
memoriesinto local storage (the same ID may appear multiple times across syncs if it is updated repeatedly — always use the latest version). - Remove any IDs in the
deletedarray from local storage. - Save the new
cursorvalue, replacing the previous one.
The deleted array is only present on incremental responses. On a full pull (no since), all returned memories are active and there is nothing to remove.
Rate Limits
The Memory API enforces a rate limit of 60 requests per minute per credential. Exceeding the limit returns 429 Too Many Requests with a Retry-After header indicating when the next request can be made.
Error Reference
All errors return a JSON body with an error string field.
{
"error": "content is required"
}| Status | Meaning |
|---|---|
400 | Bad request — missing/invalid X-Organization-Id header, missing or invalid content, unrecognized user UUID, or no fields provided to PATCH |
401 | Missing, invalid, or expired authorization credential |
403 | Account suspended, banned, or the credential does not belong to a member of the specified organization |
404 | Memory ID not found, or the memory feature is not enabled for this organization |
409 | Concurrent edit conflict (shipping in a forthcoming release; see PATCH note above) |
429 | Rate limit exceeded — check the Retry-After header |
500 | Internal server error |
Related
- Authentication - API key setup
- API Overview - Getting started with the Platform API
- Error Handling - Handle API errors