> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Customer Memory: inspect and curate what your AI agents remember

> Browse the long-term memory your AI agents accumulate per contact, curate individual entries, teach facts manually, and honour erasure requests — from the dashboard or the API.

# Customer Memory

Customer Memory is the tenant-wide record of what your AI agents have learned about each contact: facts they stated, preferences they expressed, goals they mentioned, and conversation summaries the runtime wrote. Every agent you run reads from and writes to this shared, per-contact store — so a fact an SMS agent captured last week is what a voice agent picks up on today.

The [memory plane](/agents/memory-plane) page covers how retrieval works inside a live turn. This page covers the operator side: the **AI Agents → Customer Memory** browser at `/agents/memory`, how entries get their importance, how to curate them, and the API that backs the whole surface.

## How memory accumulates

Entries land in four types, written by the agent runtime as conversations happen:

| Type         | Written when                                                               |
| ------------ | -------------------------------------------------------------------------- |
| `fact`       | The contact stated a verifiable fact (an account number, an order date).   |
| `preference` | The contact expressed a preference (callback window, channel, language).   |
| `goal`       | The contact stated a goal (cancel a contract, upgrade a plan).             |
| `summary`    | A conversation ended and the runtime compressed it into a durable summary. |

Two safeguards keep the store sane over time:

* **Importance scores (0–1).** Every entry carries an importance value. When the store comes under its per-contact budget, low-importance entries are evicted first. Manual entries land at 0.9 by default, so an operator-authored fact outlives an auto-extracted summary.
* **Per-contact caps.** There is a hard cap on `fact` entries per contact; when a tenant reaches it the API rejects new facts with a 422 rather than silently growing the contact's plane. Summaries, preferences, and goals stay under the wider sweep eviction instead.

## The `/agents/memory` browser

Open **AI Agents → Customer Memory**. The page lists memory entries across your whole tenant — every agent, every contact — as cards showing the content, type, and importance of each entry.

The filter bar narrows the grid:

* **Contact ID** — show only one contact's entries (`cnt_…`).
* **Agent ID** — show only entries one agent wrote (`agt_…`).
* **Type** — fact, preference, goal, or summary.
* **From / To** — a creation-date range. If the From date is later than the To date, the page flags the range inline and ignores it until you fix it — other filters still apply.

Entries load 50 at a time. When more exist, a **Load more** button extends the list, and the counter above the grid reports how many entries you've loaded against the scanned total. Dates and contact IDs are debounced as you type, so a pasted contact ID issues one fetch, not one per character.

Click a card to open the full entry: the complete content, type, importance, contact and agent IDs, creation time, and the entry ID. A **View conversation** link on each card deep-links into the conversation the entry was extracted from.

* **Empty tenant** — before any agent has written memory, the page shows a zero state explaining what will appear.
* **Filtered, no matches** — when filters exclude everything, the page offers to clear them instead of implying the tenant has no memory at all.

## Curating entries

Each card carries three actions:

* **Promote** — raises the entry's importance by 0.1 (capped at 1.0) in place, so it survives budget eviction longer. The same entry updates; no duplicate is created.
* **Delete** — removes the entry after a confirmation. Owner/admin roles only.
* **Add memory** — the header button teaches a fact manually. Pick the contact, the agent it belongs to, the type, and the content. The entry is embedded the same way an LLM-extracted one is, so retrieval treats it identically.

Delete and Promote are written through as `DELETE` / `PATCH` on the entry, so an entry past the 1,000-item scroll cap is still reachable — bulk browsing caps do not gate single-entry actions.

## Erasure and opt-out

Enter a Contact ID in the filter bar and, once the entries load, an **Erase contact memory** panel appears below the grid. Confirming it:

1. Deletes every memory entry the tenant holds on that contact.
2. Flips the contact's memory consent flag off, so the agent runtime stops writing new entries for them — this is the GDPR right-to-erasure path and it closes the race where a live conversation could write a fresh entry right after the wipe.

Use this for a data-subject request. When a contact has opted out, the [Profile API](/agents/memory-plane#gdpr-consent-and-erasure) and the per-agent memory tab both show the opted-out state explicitly rather than listing entries.

## Access roles

The page is gated to **owner and admin**, because it surfaces notes across the whole tenant — the same RoleGuard that gates the other AI-hub operator surfaces. Writes (create, promote, delete, erase) require owner/admin on the API as well. Reads through the Profile-API surface accept owner, admin, and developer with the `contacts:read` scope.

## How an agent uses memory at runtime

On each new turn the memory plane resolves the contact, retrieves their top entries, and renders them as a system-level block with a fixed marker:

```text theme={null}
Customer memory (from past interactions):
- prefers SMS callbacks over email
- asked for a late-evening callback window
- goal: cancel the legacy contract
```

The executor strips the previous turn's block before attaching the fresh one, so memory never accumulates inside a conversation. Curating an entry in the dashboard changes what every agent sees on its very next turn — Promote makes it rank higher in retrieval; Delete removes it from context; an added fact is available immediately.

## API surface

Everything the dashboard does, the public API does. Writes require owner or admin; requests are authenticated with your session token or API key.

| Operation                                           | Endpoint                                       |
| --------------------------------------------------- | ---------------------------------------------- |
| List entries (filter by contact, agent, type, date) | `GET /api/v1/agents/memory`                    |
| Fetch a single entry                                | `GET /api/v1/agents/memory/:id`                |
| Create a manual entry                               | `POST /api/v1/agents/memory`                   |
| Promote (raise importance)                          | `PATCH /api/v1/agents/memory/:id`              |
| Delete a single entry                               | `DELETE /api/v1/agents/memory/:id`             |
| Erase a contact's memory                            | `DELETE /api/v1/agents/memory?contactId=cnt_…` |

List entries, newest first, paged with an opaque cursor:

```bash theme={null}
curl -sG 'https://api.orbit.devotel.io/api/v1/agents/memory' \
  -H 'Authorization: Bearer '$(get_jwt) \
  --data-urlencode 'contactId=cnt_01J8Z9K3P4Q5R6S7T8U9V0W1X2' \
  --data-urlencode 'memoryType=preference' \
  --data-urlencode 'limit=50'
```

The response returns `items`, the `next_cursor` for the following page, a `total_scanned` count, and the echo of the applied filter. An invalid filter shape is a 422.

Teach a fact manually:

```bash theme={null}
curl -X POST 'https://api.orbit.devotel.io/api/v1/agents/memory' \
  -H 'Authorization: Bearer '$(get_jwt) \
  -H 'Content-Type: application/json' \
  -d '{
    "contactId": "cnt_01J8Z9K3P4Q5R6S7T8U9V0W1X2",
    "agentId": "agt_01J8Z9K3P4Q5R6S7T8U9V0W1X2",
    "memoryType": "preference",
    "content": "Customer asked to be contacted only after 6pm local time"
  }'
```

Raise an entry's importance (promote):

```bash theme={null}
curl -X PATCH 'https://api.orbit.devotel.io/api/v1/agents/memory/mem_01J8Z9K3P4Q5R6S7T8U9V0W1X2' \
  -H 'Authorization: Bearer '$(get_jwt) \
  -H 'Content-Type: application/json' \
  -d '{ "importance": 0.95 }'
```

Erase a contact — the right-to-erasure request path:

```bash theme={null}
curl -X DELETE 'https://api.orbit.devotel.io/api/v1/agents/memory?contactId=cnt_01J8Z9K3P4Q5R6S7T8U9V0W1X2' \
  -H 'Authorization: Bearer '$(get_jwt)
```

A cross-tenant or unknown entry id is a deliberate 404 on every single-entry route. For read-only, cross-channel surfacing of one contact's memory to your own systems, use the [Profile API memory endpoints](/agents/memory-plane#reading-memory-through-the-cdp-profile-api) — those accept the developer role and return masked content by default.

## Next steps

* [Memory plane](/agents/memory-plane) — resolution, retrieval, and rendering inside a live turn.
* [Agent guardrails](/agents/guardrail-effectiveness) — combine curated memory with the guardrail stack.
* [Audit log](/guides/audit-log) — every reveal, delete, and erase writes an auditable entry there.
