# Memory

> Remember, recall, supersede, forget and consolidate memories.

Source: https://useprimitives.com/docs/api/memory

These routes apply to a primitive of type `memory`, a store of typed memories with hybrid recall. See [Memory](/docs/primitives/memory) for the concepts. Calling one of them on a primitive of another type answers `400 wrong_type`.

| Method | Path | Description |
| --- | --- | --- |
| `POST` | `/v1/primitives/{id}/memories` | Remember |
| `GET` | `/v1/primitives/{id}/memories` | List memories |
| `GET` | `/v1/primitives/{id}/memories/{memory}` | Get a memory |
| `DELETE` | `/v1/primitives/{id}/memories/{memory}` | Forget a memory |
| `POST` | `/v1/primitives/{id}/memories/{memory}/supersede` | Supersede a memory |
| `POST` | `/v1/primitives/{id}/recall` | Recall |
| `POST` | `/v1/primitives/{id}/consolidate` | Merge duplicates |

`{id}` is the memory primitive's id and `{memory}` a memory's id.

Every route answers `423 paused` while the primitive is paused. Timestamps are milliseconds since the Unix epoch. See [Errors](/docs/api/errors) for the full list of codes.

When the engine has embeddings configured, `remember` and `supersede` store a vector for each memory and `recall` embeds the query. Without them, recall is BM25 full-text search. A failing embeddings provider never fails a request: the memory is stored without a vector and recall falls back to full text. See [Embeddings](/docs/primitives/memory#embeddings).

## Remember

`POST /v1/primitives/{id}/memories`

Stores a memory. Tags are trimmed and duplicates dropped. `embedding_model` names the model that embedded the text, or is `null` when the memory has no vector.

An unknown `kind`, empty or oversized `text`, invalid tags or owner, or `metadata` that isn't an object answers `400 invalid_request`. On a Starter workspace at its storage cap, it answers `429 plan_limit`; see [Usage and limits](/docs/api/limits#usage-and-limits).

Key tool: `memory_remember`.

**Body**

| Parameter | Type | Description |
| --- | --- | --- |
| `kind` | string | Required. `episodic`, `semantic` or `procedural`. |
| `text` | string | Required. The memory, up to 32 KiB. Must not be blank. |
| `tags` | string[] | Up to 32 tags of 1–64 characters, for filtering. Default `[]`. |
| `owner` | string | 1–256 characters, such as a user or agent id. Recall and list can filter on it. |
| `metadata` | object | Any JSON object, such as provenance. |

```bash
curl -X POST https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/memories \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "semantic", "text": "User prefers pnpm over npm", "tags": ["preferences"], "owner": "user-17", "metadata": {"source": "chat:2026-10-01"}}'
```

Returns `201` with the Memory:

```json
{
  "id": "01jc0b7q3m9w2e5r8t4y6p1s0k",
  "kind": "semantic",
  "text": "User prefers pnpm over npm",
  "tags": ["preferences"],
  "owner": "user-17",
  "metadata": { "source": "chat:2026-10-01" },
  "embedding_model": null,
  "superseded_by": null,
  "created_at": 1760486400000,
  "updated_at": 1760486400000
}
```

## List memories

`GET /v1/primitives/{id}/memories`

Lists memories newest first, optionally filtered. Superseded memories are included, with `superseded_by` set. Paged; see [Pagination](/docs/api#pagination). An unknown `kind` or `cursor` answers `400 invalid_request`.

Key tool: `memory_recall`.

**Query parameters**

| Parameter | Type | Description |
| --- | --- | --- |
| `kind` | string | Only this kind. |
| `tag` | string | Only memories with this tag. |
| `owner` | string | Only this owner's memories. |
| `limit` | integer | Page size. Default `50`, max `200`. |
| `cursor` | string | The `next_cursor` of the previous page. |

```bash
curl "https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/memories?kind=semantic&tag=preferences&limit=50" \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY"
```

```json
{
  "data": [
    {
      "id": "01jc0b7q3m9w2e5r8t4y6p1s0k",
      "kind": "semantic",
      "text": "User prefers pnpm over npm",
      "tags": ["preferences"],
      "owner": "user-17",
      "metadata": { "source": "chat:2026-10-01" },
      "embedding_model": null,
      "superseded_by": null,
      "created_at": 1760486400000,
      "updated_at": 1760486400000
    }
  ],
  "next_cursor": null
}
```

## Get a memory

`GET /v1/primitives/{id}/memories/{memory}`

Returns one memory, superseded or not. An unknown id answers `404 not_found`.

Key tool: `memory_recall`.

```bash
curl https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/memories/01jc0b7q3m9w2e5r8t4y6p1s0k \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY"
```

```json
{
  "id": "01jc0b7q3m9w2e5r8t4y6p1s0k",
  "kind": "semantic",
  "text": "User prefers pnpm over npm",
  "tags": ["preferences"],
  "owner": "user-17",
  "metadata": { "source": "chat:2026-10-01" },
  "embedding_model": null,
  "superseded_by": null,
  "created_at": 1760486400000,
  "updated_at": 1760486400000
}
```

## Forget a memory

`DELETE /v1/primitives/{id}/memories/{memory}`

Deletes a memory. A memory that doesn't exist answers `404 not_found`. To correct a fact while keeping its history, [supersede](#supersede-a-memory) it instead.

Key tool: `memory_forget`.

```bash
curl -X DELETE https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/memories/01jc0b7q3m9w2e5r8t4y6p1s0k \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY"
```

Returns `204` with no body.

## Supersede a memory

`POST /v1/primitives/{id}/memories/{memory}/supersede`

Stores a new memory and marks `{memory}` as superseded by it. The new memory replaces the old one in recall; the old one stays readable, with `superseded_by` set to the new id.

`kind`, `tags` and `metadata` carry over from the old memory unless given. `owner` always carries over. An unknown id answers `404 not_found`, and a memory that's already superseded answers `409 conflict`. On a Starter workspace at its storage cap, it answers `429 plan_limit`; see [Usage and limits](/docs/api/limits#usage-and-limits).

Key tool: `memory_forget`.

**Body**

| Parameter | Type | Description |
| --- | --- | --- |
| `text` | string | Required. The new memory, up to 32 KiB. |
| `kind` | string | `episodic`, `semantic` or `procedural`. Default the old memory's. |
| `tags` | string[] | Replaces the tags. Default the old memory's. |
| `metadata` | object | Replaces the metadata. Default the old memory's. |

```bash
curl -X POST https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/memories/01jc0b7q3m9w2e5r8t4y6p1s0k/supersede \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "User now prefers bun"}'
```

Returns `201` with the new Memory:

```json
{
  "id": "01jc0c2h6k8n4p7r9t3v5x1z0a",
  "kind": "semantic",
  "text": "User now prefers bun",
  "tags": ["preferences"],
  "owner": "user-17",
  "metadata": { "source": "chat:2026-10-01" },
  "embedding_model": null,
  "superseded_by": null,
  "created_at": 1760490000000,
  "updated_at": 1760490000000
}
```

## Recall

`POST /v1/primitives/{id}/recall`

Searches memories and returns the best matches, best first, in one response. Recall ranks memories with BM25 over their text and tags and, given embeddings, with cosine similarity over their vectors, then fuses the two rankings with Reciprocal Rank Fusion (k = 60). `bm25_rank` and `vector_rank` are each hit's 1-based position in each ranking, or `null` if it wasn't in that list. `score` is the fused score.

A `query` with no words returns the most recent matching memories, each with `score` `0`. Superseded memories are left out unless `include_superseded` is `true`. An unknown kind answers `400 invalid_request`.

Key tool: `memory_recall`.

**Body**

| Parameter | Type | Description |
| --- | --- | --- |
| `query` | string | What to look for. Default `""`, which returns the most recent memories. |
| `kinds` | string[] | Only these kinds. Default all. |
| `tags` | string[] | Every tag must be present on the memory. |
| `owner` | string | Only this owner's memories. |
| `limit` | integer | Default `10`, max `50`. |
| `include_superseded` | boolean | Also return superseded memories. Default `false`. |

```bash
curl -X POST https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/recall \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "which package manager?", "kinds": ["semantic"], "limit": 5}'
```

```json
{
  "data": [
    {
      "memory": {
        "id": "01jc0c2h6k8n4p7r9t3v5x1z0a",
        "kind": "semantic",
        "text": "User now prefers bun",
        "tags": ["preferences"],
        "owner": "user-17",
        "metadata": { "source": "chat:2026-10-01" },
        "embedding_model": null,
        "superseded_by": null,
        "created_at": 1760490000000,
        "updated_at": 1760490000000
      },
      "score": 0.01639344262295082,
      "bm25_rank": 1,
      "vector_rank": null
    }
  ]
}
```

## Merge duplicates

`POST /v1/primitives/{id}/consolidate`

Merges duplicates among active memories of the same kind and owner. Two memories are duplicates when their normalized text is identical, or when both have embeddings with cosine similarity at or above `threshold`. The newest memory of each cluster is kept and the others are superseded by it. Nothing is deleted. The body is optional.

Returns `merged`, the number of kept memories that absorbed at least one duplicate, and `superseded`, the ids of the memories marked superseded. A `threshold` outside `(0, 1]` answers `400 invalid_request`. On a Starter workspace at its storage cap, it answers `429 plan_limit`; see [Usage and limits](/docs/api/limits#usage-and-limits).

Key tool: `memory_forget`.

**Body**

| Parameter | Type | Description |
| --- | --- | --- |
| `threshold` | number | Cosine similarity for near-duplicates, greater than `0` and at most `1`. Default `0.95`. |

```bash
curl -X POST https://api.useprimitives.com/v1/primitives/01jbz3k8m5q2w7x9v4n6t0r1ce/consolidate \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"threshold": 0.9}'
```

```json
{
  "merged": 1,
  "superseded": ["01jc0b9t5w2k7m4p8r3v6x1z0d"]
}
```

## Shapes

| Shape | Fields |
| --- | --- |
| Memory | `{ id, kind, text, tags, owner, metadata, embedding_model, superseded_by, created_at, updated_at }`. `kind` is `episodic`, `semantic` or `procedural`. `tags` is an array of strings. `owner`, `metadata`, `embedding_model` and `superseded_by` may be `null`. `superseded_by` is the id of the memory that replaced this one. The vector itself is never returned |
| RecallHit | `{ memory, score, bm25_rank, vector_rank }`. `memory` is a Memory, `score` a number, and each rank a 1-based number or `null` |
| ConsolidateResult | `{ merged, superseded }`. `merged` is a number, `superseded` an array of memory ids |

Scoped API keys need the tool named in each section on their allowlist; see [Tool allowlists](/docs/api/authentication#tool-allowlists). For creating, snapshotting, forking and pausing the memory primitive itself, see [Primitives](/docs/api/primitives). See [Limits](/docs/api/limits) for how operations are counted.
