diff --git a/apps/docs/add-memories.mdx b/apps/docs/add-memories.mdx
index e8f02878..3ec212d4 100644
--- a/apps/docs/add-memories.mdx
+++ b/apps/docs/add-memories.mdx
@@ -112,7 +112,7 @@ Both work — choose what fits your architecture.
### Replace entire document
-To completely replace a document's content (not append), use `memories.update()`:
+To completely replace a document's content (not append), use `documents.update()`:
```typescript
// Replace the entire document content
diff --git a/apps/docs/concepts/customization.mdx b/apps/docs/concepts/customization.mdx
index 5d3ff7f7..cc27ebe7 100644
--- a/apps/docs/concepts/customization.mdx
+++ b/apps/docs/concepts/customization.mdx
@@ -63,13 +63,12 @@ Inline, when you add content:
```typescript TypeScript
-await client.memories.add({
+await client.add({
content: "Asked about logo variations for dark backgrounds again — leaning toward the mono version.",
containerTag: "user_4f8a",
entityContext: `Design conversations between john@acme.com and the Brand.ai assistant.
"The logo" means Acme's primary mark. Focus on John's design preferences and constraints.`,
});
-// entityContext isn't in the SDK's TS typings yet — the API accepts it
```
```bash cURL
@@ -85,8 +84,6 @@ curl -X POST https://api.supermemory.ai/v3/documents \
-
-
Or directly on the tag, without ingesting anything. The TS SDK doesn't expose a container-tag update method yet, so this one is a REST call:
```bash cURL
@@ -98,7 +95,7 @@ curl -X PATCH https://api.supermemory.ai/v3/container-tags/user_4f8a \
}'
```
-
+
Either way, entity context **persists on the tag**. Pass it on one `add()` call and it's stored — every future document in that container is processed with it, including connector syncs landing in the same tag, until you overwrite it or set it to `null`. It's tag state, not a per-request option. If that's not what you expected, it's the one behavior on this page worth rereading.
diff --git a/apps/docs/concepts/glossary.mdx b/apps/docs/concepts/glossary.mdx
index af1b9e59..5402745b 100644
--- a/apps/docs/concepts/glossary.mdx
+++ b/apps/docs/concepts/glossary.mdx
@@ -14,7 +14,7 @@ import Supermemory from "supermemory"
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
-await client.memories.add({
+await client.add({
content: "Sarah's being promoted to VP of Product", // becomes a document
containerTag: "user_4f8a", // the isolation boundary
customId: "slack-thread-9917", // your stable id for this document
@@ -27,7 +27,7 @@ from supermemory import Supermemory
client = Supermemory()
-client.memories.add(
+client.add(
content="Sarah's being promoted to VP of Product",
container_tag="user_4f8a",
custom_id="slack-thread-9917",
@@ -49,8 +49,6 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-{/* CONFIRM: python — memories.add kwargs mirrored from the published pypi search style; verify against the shipped package */}
-
The content becomes a **document**, the pipeline derives **memories** from it, the memories join the **graph**, and the **profile** for `user_4f8a` updates. The rest of this page defines each of those words — plus the ones that control the process.
## From content to memory
@@ -65,7 +63,7 @@ An individual fact derived from your documents by the ingestion pipeline — a c
### Chunk
-A slice of a document, sized for retrieval. Search matches at the chunk level, so you get the relevant passage instead of a 40-page document. On memory search you pull them with `include: { chunks: true }`; document search returns matching chunks directly. How chunks, memories, and the graph combine at query time is the subject of [hybrid search](/concepts/hybrid-search).
+A slice of a document, sized for retrieval. Search matches at the chunk level, so you get the relevant passage instead of a 40-page document. On memory search you pull them in with `searchMode: "hybrid"`; document search returns matching chunks directly. How chunks, memories, and the graph combine at query time is the subject of [hybrid search](/concepts/hybrid-search).
### Dreaming
diff --git a/apps/docs/concepts/graph-memory.mdx b/apps/docs/concepts/graph-memory.mdx
index 61bc3c80..98da7d35 100644
--- a/apps/docs/concepts/graph-memory.mdx
+++ b/apps/docs/concepts/graph-memory.mdx
@@ -16,13 +16,13 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
-await client.memories.add({
+await client.add({
content: "Sarah's favorite color is red",
containerTag: "user_4f8a",
});
// three weeks later
-await client.memories.add({
+await client.add({
content: "Sarah said she's over red — black is her favorite now",
containerTag: "user_4f8a",
});
@@ -40,13 +40,13 @@ from supermemory import Supermemory
client = Supermemory()
-client.memories.add(
+client.add(
content="Sarah's favorite color is red",
container_tag="user_4f8a",
)
# three weeks later
-client.memories.add(
+client.add(
content="Sarah said she's over red — black is her favorite now",
container_tag="user_4f8a",
)
diff --git a/apps/docs/concepts/how-it-works.mdx b/apps/docs/concepts/how-it-works.mdx
index bb8e62d2..8a57383d 100644
--- a/apps/docs/concepts/how-it-works.mdx
+++ b/apps/docs/concepts/how-it-works.mdx
@@ -17,7 +17,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
-const doc = await client.memories.add({
+const doc = await client.add({
content:
"Notes from the Tokyo offsite: Sarah presented the Q3 roadmap to the exec team and it landed well. She's currently our design lead.",
containerTag: "user_4f8a",
@@ -32,7 +32,7 @@ from supermemory import Supermemory
client = Supermemory()
-doc = client.memories.add(
+doc = client.add(
content="Notes from the Tokyo offsite: Sarah presented the Q3 roadmap to the exec team and it landed well. She's currently our design lead.",
container_tag="user_4f8a",
)
@@ -50,7 +50,6 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-
The call returns immediately with an `id` and a status of `queued`. Processing happens asynchronously — you don't wait on ingestion to serve your users.
@@ -78,22 +77,22 @@ Poll the document until it's done:
```typescript TypeScript
-let status = await client.memories.get(doc.id);
+let status = await client.documents.get(doc.id);
while (status.status !== "done" && status.status !== "failed") {
await new Promise((r) => setTimeout(r, 2000));
- status = await client.memories.get(doc.id);
+ status = await client.documents.get(doc.id);
}
```
```python Python
import time
-status = client.memories.get(doc.id)
+status = client.documents.get(doc.id)
while status.status not in ("done", "failed"):
time.sleep(2)
- status = client.memories.get(doc.id)
+ status = client.documents.get(doc.id)
```
```bash cURL
@@ -165,7 +164,7 @@ This is where supermemory stops behaving like a vector store. A second document
```typescript TypeScript
-await client.memories.add({
+await client.add({
content:
"Sarah's being promoted to VP of Product. She starts the new role next month.",
containerTag: "user_4f8a",
@@ -173,7 +172,7 @@ await client.memories.add({
```
```python Python
-client.memories.add(
+client.add(
content="Sarah's being promoted to VP of Product. She starts the new role next month.",
container_tag="user_4f8a",
)
@@ -249,8 +248,6 @@ curl -X DELETE "https://api.supermemory.ai/v4/memories" \
-
-
Forgotten memories stop appearing in search — unless you ask for them back with `include: { forgottenMemories: true }` on `client.search.memories`. That's the escape hatch when a forget was wrong.
For bulk cleanup there's `POST /v4/memories/forget-matching`: you give it a natural-language query ("forget everything about Project Titan"), an agent searches the container and soft-forgets the matches. It caps at 100 memories per call by default (500 max, via `maxForget`), and `dryRun: true` returns what *would* be forgotten without touching anything. Always dry-run first:
@@ -271,11 +268,11 @@ curl -X POST "https://api.supermemory.ai/v4/memories/forget-matching" \
```typescript TypeScript
-await client.memories.delete("doc_x1k2m9");
+await client.documents.delete("doc_x1k2m9");
```
```python Python
-client.memories.delete("doc_x1k2m9")
+client.documents.delete("doc_x1k2m9")
```
```bash cURL
diff --git a/apps/docs/concepts/hybrid-search.mdx b/apps/docs/concepts/hybrid-search.mdx
index 27bf3918..2f7f787f 100644
--- a/apps/docs/concepts/hybrid-search.mdx
+++ b/apps/docs/concepts/hybrid-search.mdx
@@ -86,6 +86,51 @@ The response is ranked memories, not chunks:
Search returns the top N — there's no pagination. If you need to walk everything in a container, list documents instead.
+## Blend in document chunks: `searchMode`
+
+By default, `search.memories` returns memories only — derived facts, no raw chunks. `searchMode` is the mode selector that decides what comes back:
+
+
+```typescript TypeScript
+const results = await client.search.memories({
+ q: "what does Sarah do at the company?",
+ containerTag: "user_4f8a",
+ searchMode: "hybrid", // memories + the chunks that back them
+});
+```
+
+```python Python
+results = client.search.memories(
+ q="what does Sarah do at the company?",
+ container_tag="user_4f8a",
+ search_mode="hybrid",
+)
+```
+
+```bash cURL
+curl -X POST "https://api.supermemory.ai/v4/search" \
+ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "q": "what does Sarah do at the company?",
+ "containerTag": "user_4f8a",
+ "searchMode": "hybrid"
+ }'
+```
+
+
+The three modes:
+
+| `searchMode` | Returns |
+|---|---|
+| `memories` (default) | Derived memories only |
+| `hybrid` | Memories **and** the document chunks that back them |
+| `documents` | Document chunks only — no memories |
+
+If your search results seem biased toward one source, or you're getting facts back but none of the underlying chunk content to cite, this is the knob you're missing. `memories` is deliberately lean. Switch to `hybrid` when you want the fact and the passage it came from in a single v4 call, or `documents` when you only need raw chunks.
+
+`include: { chunks: true }` does the same thing and is kept for back-compat — it auto-switches the call to `hybrid`. It's deprecated; reach for `searchMode: "hybrid"` in new code.
+
## Search documents
When you want the source content itself — RAG, citations, "find the clause" — search documents:
@@ -235,7 +280,6 @@ const results = await client.search.memories({
containerTag: "user_4f8a",
include: {
documents: true, // source document + its metadata
- chunks: true, // relevant chunks from those documents
relatedMemories: true, // graph neighbors of each memory
summaries: true, // document summaries
},
@@ -248,7 +292,6 @@ results = client.search.memories(
container_tag="user_4f8a",
include={
"documents": True,
- "chunks": True,
"related_memories": True,
"summaries": True,
},
@@ -264,7 +307,6 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
"containerTag": "user_4f8a",
"include": {
"documents": true,
- "chunks": true,
"relatedMemories": true,
"summaries": true
}
@@ -272,8 +314,6 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
```
-
-
The one that catches people: **metadata lives on documents, not memories.** A memory's `metadata` field reflects its source document — so if you need document metadata (titles, your custom fields) alongside memory results, set `include: { documents: true }` rather than making a second call.
Two more worth knowing:
@@ -281,7 +321,7 @@ Two more worth knowing:
- `relatedMemories` pulls in graph neighbors — memories connected to your hits. If your recall feels like it's returning the fact but missing its context, this is usually the fix.
- `forgottenMemories` includes memories that were explicitly forgotten or expired past their TTL. Off by default, which is what you want; turn it on for audit or debugging views. [Graph memory](/concepts/graph-memory) covers how forgetting works.
-`include: { chunks: true }` is also the fast path for "memories plus supporting evidence": one v4 call instead of a memory search followed by per-document fetches.
+For "memories plus supporting evidence" — the fact and the chunk it came from in one v4 call instead of a memory search followed by per-document fetches — use [`searchMode: "hybrid"`](#blend-in-document-chunks-searchmode). (`include: { chunks: true }` still works and auto-switches to hybrid, but it's deprecated back-compat.)
## Filter with metadata
diff --git a/apps/docs/concepts/permissioning.mdx b/apps/docs/concepts/permissioning.mdx
index a0938d6f..df7809e9 100644
--- a/apps/docs/concepts/permissioning.mdx
+++ b/apps/docs/concepts/permissioning.mdx
@@ -17,7 +17,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
// POST /v3/documents
-await client.memories.add({
+await client.add({
content: "Sarah's being promoted to VP of Product in March",
containerTag: "user_4f8a", // the isolation boundary
metadata: {
@@ -96,7 +96,7 @@ Agent role is a dimension, not a boundary. The fix:
```typescript
// one container per tenant, role as metadata
-await client.memories.add({
+await client.add({
content: "Customer confirmed they're migrating off Postgres by Q3",
containerTag: "org_acme",
metadata: { agent_role: "support" },
@@ -239,7 +239,7 @@ The default architecture. One container per user, tag derived from your own auth
```typescript
const tag = `user_${session.user.id}`;
-await client.memories.add({
+await client.add({
content: message.content,
containerTag: tag,
customId: conversationId, // same conversation, same document
@@ -261,14 +261,14 @@ The hybrid every team product needs: facts the whole org should know, plus facts
```typescript
// shared knowledge → the org container
-await client.memories.add({
+await client.add({
content: "We ship releases on Thursdays; hotfixes anytime",
containerTag: "org_acme",
metadata: { team: "platform" },
});
// private facts → the user's container
-await client.memories.add({
+await client.add({
content: "Priya prefers async standups and no meetings before 10am",
containerTag: "user_priya",
});
@@ -298,7 +298,7 @@ Multiple agents serving one tenant share that tenant's container (the anti-patte
3. **A handoff-summary memory with a stable `customId`.** When one agent hands off to another, it writes a summary of state; the stable ID means each handoff updates the same document instead of piling up near-duplicates:
```typescript
-await client.memories.add({
+await client.add({
content: "Handoff: customer verified, refund approved for $240, awaiting card confirmation",
containerTag: "org_acme",
customId: "handoff_ticket_8813", // same id on every update → one document
diff --git a/apps/docs/connectors/overview.mdx b/apps/docs/connectors/overview.mdx
index e7c0191b..a76bbb6a 100644
--- a/apps/docs/connectors/overview.mdx
+++ b/apps/docs/connectors/overview.mdx
@@ -110,7 +110,7 @@ for (const conn of connections) {
}
// then verify the imported documents themselves
-const docs = await client.memories.list({
+const docs = await client.documents.list({
containerTags: ['user_4f8a'],
});
```
@@ -122,7 +122,7 @@ for conn in connections:
print(conn.provider, conn.email, conn.created_at)
# then verify the imported documents themselves
-docs = client.memories.list(container_tags=['user_4f8a'])
+docs = client.documents.list(container_tags=['user_4f8a'])
```
```bash cURL
diff --git a/apps/docs/docs.json b/apps/docs/docs.json
index cfcdbfc9..825debb5 100644
--- a/apps/docs/docs.json
+++ b/apps/docs/docs.json
@@ -8,8 +8,7 @@
"python",
"curl"
]
- },
- "openapi": "https://api.supermemory.ai/v3/openapi"
+ }
},
"colors": {
"dark": "#1E3A8A",
@@ -291,8 +290,7 @@
"anchors": [
{
"anchor": "API Reference",
- "icon": "unplug",
- "openapi": "https://api.supermemory.ai/v3/openapi"
+ "icon": "unplug"
}
],
"tab": "API Reference"
diff --git a/apps/docs/intro.mdx b/apps/docs/intro.mdx
index d05d99c6..9bea4f8a 100644
--- a/apps/docs/intro.mdx
+++ b/apps/docs/intro.mdx
@@ -16,7 +16,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
-await client.memories.add({
+await client.add({
content: "Sarah's being promoted to VP of Product",
containerTag: "user_4f8a",
});
@@ -32,7 +32,7 @@ from supermemory import Supermemory
client = Supermemory()
-client.memories.add(
+client.add(
content="Sarah's being promoted to VP of Product",
container_tag="user_4f8a",
)
diff --git a/apps/docs/llms.txt b/apps/docs/llms.txt
index fae1ddf9..693147d1 100644
--- a/apps/docs/llms.txt
+++ b/apps/docs/llms.txt
@@ -36,7 +36,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
// add — POST /v3/documents
-await client.memories.add({
+await client.add({
content: "Sarah's being promoted to VP of Product",
containerTag: "user_4f8a", // singular, always
metadata: { channel: "slack" }, // dimensions within the boundary
diff --git a/apps/docs/migration/from-mem0.mdx b/apps/docs/migration/from-mem0.mdx
index d662a6f3..d0ddbd15 100644
--- a/apps/docs/migration/from-mem0.mdx
+++ b/apps/docs/migration/from-mem0.mdx
@@ -36,7 +36,7 @@ data = mem0.get_memory_export(memory_export_id=export["id"])
supermemory = Supermemory(api_key="your_supermemory_api_key")
for memory in data["memories"]:
if memory.get("content"):
- supermemory.memories.add(
+ supermemory.add(
content=memory["content"],
container_tag="imported_from_mem0"
)
diff --git a/apps/docs/patterns/agent-task-memory.mdx b/apps/docs/patterns/agent-task-memory.mdx
index d010a955..904455c8 100644
--- a/apps/docs/patterns/agent-task-memory.mdx
+++ b/apps/docs/patterns/agent-task-memory.mdx
@@ -183,8 +183,6 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
-
-
When the configuration is right, results read like operational knowledge:
```json
diff --git a/apps/docs/patterns/ai-companion.mdx b/apps/docs/patterns/ai-companion.mdx
index 973a28a2..50a101ee 100644
--- a/apps/docs/patterns/ai-companion.mdx
+++ b/apps/docs/patterns/ai-companion.mdx
@@ -40,7 +40,7 @@ Then add the whole window with a `customId` that names the session:
```ts TypeScript
-await client.memories.add({
+await client.add({
content: transcript,
containerTag: "user_4f8a",
customId: "session_user_4f8a_1752742800",
diff --git a/apps/docs/patterns/company-brain.mdx b/apps/docs/patterns/company-brain.mdx
index a2ba88cf..b1521af6 100644
--- a/apps/docs/patterns/company-brain.mdx
+++ b/apps/docs/patterns/company-brain.mdx
@@ -134,9 +134,7 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
-
-
-And the reverse works too: `client.memories.add({ content, containerTag: "team_growth" })` puts a memory into the same brain the team is asking questions of. If they want to feed it programmatically — internal tools, ETL from systems without a connector — the [ingestion patterns](/patterns/ingestion) page covers how to do that well.
+And the reverse works too: `client.add({ content, containerTag: "team_growth" })` puts a memory into the same brain the team is asking questions of. If they want to feed it programmatically — internal tools, ETL from systems without a connector — the [ingestion patterns](/patterns/ingestion) page covers how to do that well.
That's the whole idea: the same engine your engineers build on, with a door your entire team can walk through.
diff --git a/apps/docs/patterns/ingestion.mdx b/apps/docs/patterns/ingestion.mdx
index 18e80e67..23a6a7ac 100644
--- a/apps/docs/patterns/ingestion.mdx
+++ b/apps/docs/patterns/ingestion.mdx
@@ -22,7 +22,7 @@ Instead, give each session a `customId` and send the conversation to it as it gr
```typescript TypeScript
-await client.memories.add({
+await client.add({
content: `user: My daughter Maya got into NYU — she starts in the fall.
assistant: Congratulations! Is she excited about New York?
user: Thrilled. We're flying out August 20th to move her in.`,
@@ -54,8 +54,6 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-{/* CONFIRM: python — client.add signature mirrored from quickstart.mdx; no Python SDK in repos to verify against */}
-
When more messages arrive, send them to the same `customId` — either the new messages alone or the full updated transcript. Supermemory links them to the existing document and processes only what's new, so you're not re-paying for the turns it already saw.
This is why full-conversation ingestion is cheaper, not only better: fifty turns as one growing document is one document deriving memories from coherent context. Fifty turns as fifty documents is fifty isolated ingestion jobs, each missing the context the others hold.
@@ -63,7 +61,7 @@ This is why full-conversation ingestion is cheaper, not only better: fifty turns
Two details worth knowing:
- **Include both sides.** Assistant turns carry facts too — what was recommended, what was agreed, what the user confirmed. Strip the assistant and you lose half the session's meaning. (What *not* to learn from assistant turns — unconfirmed claims — is covered in the [AI companion pattern](/patterns/ai-companion).)
-- **`customId` constraints:** max 100 characters, alphanumeric with hyphens, underscores, and colons. Use an ID from your own database — that's what it's for.
+- **`customId` constraints:** max 100 characters, alphanumeric with hyphens, underscores, and dots. Use an ID from your own database — that's what it's for.
## Close the window at ~50 turns or ~4 hours
@@ -73,7 +71,7 @@ A session shouldn't grow forever. Past a point, one document stops being "a cohe
// derive the window from your session, not a global counter
const windowId = `chat_8821_w${session.windowIndex}`;
-await client.memories.add({
+await client.add({
content: session.transcriptSinceWindowStart,
customId: windowId,
containerTag: "user_4f8a",
@@ -203,7 +201,7 @@ The full error and limit reference is at [errors and limits](/errors-and-limits)
**Poll status before you judge the results.** Batch acceptance means *queued*, not *searchable*. Each document moves through `queued → extracting → chunking → embedding → indexing → done`, and its memories are queryable once it hits `done`. To verify an import, poll the IDs the batch returned:
```typescript
-const doc = await client.memories.get("doc_x2ka91");
+const doc = await client.documents.get("doc_x2ka91");
if (doc.status === "done") {
// memories from this document are now searchable
} else if (doc.status === "failed") {
@@ -220,7 +218,7 @@ There's no bulk "is my whole import done" call yet — poll the IDs you care abo
Where it can matter: two writes to the *same* `customId` fired in quick succession. In rare cases the second can be picked up while the first is still processing, and the updates race. Two ways to make that impossible:
- **Send the full accumulated transcript each time** instead of only the delta. Then the latest write contains everything, and whichever write lands last is complete on its own. It's the least machinery and costs little extra — unchanged content is recognized and not reprocessed.
-- **Wait for `done` before the next write** to the same `customId`, polling `client.memories.get(id)`. Use this when deltas are large and you'd rather sequence than resend.
+- **Wait for `done` before the next write** to the same `customId`, polling `client.documents.get(id)`. Use this when deltas are large and you'd rather sequence than resend.
For backfills, the batch endpoint sidesteps the question: one request, distinct `customId`s per document, no interleaved writes to the same session.
diff --git a/apps/docs/patterns/multi-agent.mdx b/apps/docs/patterns/multi-agent.mdx
index 12b4069b..84a78d77 100644
--- a/apps/docs/patterns/multi-agent.mdx
+++ b/apps/docs/patterns/multi-agent.mdx
@@ -13,7 +13,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
// the researcher writes what it found
-await client.memories.add({
+await client.add({
content: "Competitor pricing scan: Vanta starts at $7,500/yr, Drata is quote-only, both gate SSO behind enterprise tiers...",
containerTag: "proj_atlas",
customId: "ep_2041_research_notes",
@@ -34,7 +34,7 @@ from supermemory import Supermemory
client = Supermemory()
# the researcher writes what it found
-client.memories.add(
+client.add(
content="Competitor pricing scan: Vanta starts at $7,500/yr, Drata is quote-only, both gate SSO behind enterprise tiers...",
container_tag="proj_atlas",
custom_id="ep_2041_research_notes",
@@ -105,7 +105,7 @@ Each agent writes its full output — findings, drafts, decisions, not only conc
```typescript TypeScript
// the planner ships its plan into the same container
-await client.memories.add({
+await client.add({
content: "# Launch plan for Atlas\n\nWeek 1: undercut Vanta's entry tier at $5,900...",
containerTag: "proj_atlas",
customId: "ep_2041_plan_v1",
@@ -114,7 +114,7 @@ await client.memories.add({
```
```python Python
-client.memories.add(
+client.add(
content="# Launch plan for Atlas\n\nWeek 1: undercut Vanta's entry tier at $5,900...",
container_tag="proj_atlas",
custom_id="ep_2041_plan_v1",
@@ -154,7 +154,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
}'
```
-The TypeScript SDK doesn't type `filterByMetadata` yet — send it over REST until it lands. See [filtered writes](/add-memories#filtered-writes) for how the context scoping works.
+`filterByMetadata` isn't in the `supermemory@4.x` TS typings yet — the backend accepts it, so send it over REST until it lands. See [filtered writes](/add-memories#filtered-writes) for how the context scoping works.
## Filter reads per role
@@ -270,7 +270,7 @@ Filtered search gives the next agent everything upstream — but "everything" is
```typescript TypeScript
// researcher is done — write the baton
-await client.memories.add({
+await client.add({
content: `# Research handoff — Atlas ep_2041
## Decided
@@ -288,7 +288,7 @@ await client.memories.add({
```
```python Python
-client.memories.add(
+client.add(
content=handoff_markdown,
container_tag="proj_atlas",
custom_id="ep_2041_handoff_research",
@@ -340,24 +340,24 @@ Default to keeping episode memories. Cross-episode recall is most of the payoff
```typescript TypeScript
// find everything ep_2041 wrote...
-const { memories } = await client.memories.list({
+const { memories } = await client.documents.list({
containerTags: ["proj_atlas"],
filters: { AND: [{ key: "episode", value: "ep_2041" }] },
limit: 100,
});
// ...and remove it
-await Promise.all(memories.map((m) => client.memories.delete(m.id)));
+await Promise.all(memories.map((m) => client.documents.delete(m.id)));
```
```python Python
-page = client.memories.list(
+page = client.documents.list(
container_tags=["proj_atlas"],
filters={"AND": [{"key": "episode", "value": "ep_2041"}]},
limit=100,
)
for m in page.memories:
- client.memories.delete(m.id)
+ client.documents.delete(m.id)
```
```bash cURL
diff --git a/apps/docs/patterns/multi-tenant-saas.mdx b/apps/docs/patterns/multi-tenant-saas.mdx
index a77e8592..5aaf61ca 100644
--- a/apps/docs/patterns/multi-tenant-saas.mdx
+++ b/apps/docs/patterns/multi-tenant-saas.mdx
@@ -121,7 +121,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: scopedKey }); // safe in the browser
-await client.memories.add({
+await client.add({
content: sessionTranscript, // the whole session, both sides, as markdown
containerTag: "user_4f8a",
customId: "user_4f8a_session_0093",
@@ -157,8 +157,6 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-
-
Notice what `metadata` is doing: `channel` and `plan` are dimensions *within* the user's boundary — things you'll filter by at search time. They're metadata precisely because they don't need walls between them. If you catch yourself creating tags like `user_4f8a_web` and `user_4f8a_mobile`, stop: that's two containers that can't see each other, which means the assistant on mobile forgets what the user said on web. Tag = boundary, metadata = dimension. The [permissioning page](/concepts/permissioning) has the full anti-pattern gallery.
The ingestion side has its own craft — session windows, markdown over raw JSON, extracting from both turns. That's all in [ingestion best practices](/patterns/ingestion); it applies unchanged here.
@@ -175,7 +173,7 @@ Writes route by audience. Private chat goes to the user container as above. Shar
```typescript TypeScript
-await client.memories.add({
+await client.add({
content: "Decision from planning: Acme is standardizing on usage-based pricing for Q4.",
containerTag: "org_acme",
metadata: { author: "user_4f8a" },
@@ -199,7 +197,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-
+One caveat on that TypeScript tab: `filterByMetadata` isn't in the `supermemory@4.x` typed `AddParams` yet. The backend accepts it, so send it over REST until it's typed.
`filterByMetadata` is a [filtered write](/add-memories#filtered-writes): new memories are generated using only existing memories that match the filter as context. Without it, everything in `org_acme` is fair game as ingestion context, and a shared container full of many people's notes starts blending them. Pair it with `entityContext` on the org container — a one-time description like "This container holds Acme's shared workspace knowledge; individual members are contributors, not the subject" — so extraction knows the container is about the org, not any one person. `entityContext` mechanics live in [Customization](/concepts/customization).
diff --git a/apps/docs/patterns/overview.mdx b/apps/docs/patterns/overview.mdx
index 2f10dcf8..dc36f101 100644
--- a/apps/docs/patterns/overview.mdx
+++ b/apps/docs/patterns/overview.mdx
@@ -57,7 +57,7 @@ import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
// write path: the full session, both sides of the conversation
-await client.memories.add({
+await client.add({
content: sessionTranscript, // markdown ingests better than raw JSON
containerTag: "user_4f8a",
customId: "user_4f8a_session_0093",
@@ -120,8 +120,6 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
-
-
Notice what you *didn't* do: you never wrote a memory by hand. You don't decide what's worth remembering — the ingestion pipeline derives memories from what you feed it, connects them in the [graph](/concepts/graph-memory), and keeps the profile current. Your real design decisions are the ones this page is about: what to feed it, and how to partition it.
## Know the primitives
diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx
index 2bd6c4cf..b8ea73ae 100644
--- a/apps/docs/quickstart.mdx
+++ b/apps/docs/quickstart.mdx
@@ -52,7 +52,7 @@ const facts = [
];
for (const content of facts) {
- await client.memories.add({ content, containerTag: "user_4f8a" });
+ await client.add({ content, containerTag: "user_4f8a" });
}
```
@@ -234,7 +234,7 @@ while (true) {
console.log(`assistant: ${answer}`);
// store the exchange so it becomes memory for next time
- await memory.memories.add({
+ await memory.add({
content: `user: ${question}\nassistant: ${answer}`,
containerTag: "user_4f8a",
});
diff --git a/apps/docs/self-hosting/quickstart.mdx b/apps/docs/self-hosting/quickstart.mdx
index 2e4dfe60..3cb81eae 100644
--- a/apps/docs/self-hosting/quickstart.mdx
+++ b/apps/docs/self-hosting/quickstart.mdx
@@ -66,7 +66,7 @@ const client = new Supermemory({
baseURL: "http://localhost:6767",
})
-await client.memories.add({
+await client.add({
content: "I'm Dhravya. I love building dev tools and I'm allergic to peanuts.",
containerTag: "user_dhravya",
})
@@ -81,7 +81,7 @@ client = Supermemory(
base_url="http://localhost:6767",
)
-client.memories.add(
+client.add(
content="I'm Dhravya. I love building dev tools and I'm allergic to peanuts.",
container_tag="user_dhravya",
)
diff --git a/apps/docs/trust/security.mdx b/apps/docs/trust/security.mdx
index 8c9f312a..47020906 100644
--- a/apps/docs/trust/security.mdx
+++ b/apps/docs/trust/security.mdx
@@ -158,7 +158,7 @@ Deletion is permanent and there's no recovery — gate this behind your own conf
Supermemory has two removal mechanisms, and for compliance work you must use the right one:
-- **Delete (v3, document-level) is the erasure path.** `DELETE /v3/documents/:id` (`client.memories.delete(id)` in the SDK) removes one document; `DELETE /v3/documents/bulk` removes everything under a container tag. This is hard removal — use it for right-to-erasure requests.
+- **Delete (v3, document-level) is the erasure path.** `DELETE /v3/documents/:id` (`client.documents.delete(id)` in the SDK) removes one document; `DELETE /v3/documents/bulk` removes everything under a container tag. This is hard removal — use it for right-to-erasure requests.
- **Forget (v4, memory-level) is a product feature, not erasure.** `DELETE /v4/memories` and `POST /v4/memories/forget-matching` soft-delete individual derived facts: the memory stops appearing in search results but is preserved in the database (`isForgotten: true`), so the system can reason about what it used to believe. That's the right tool for "the user corrected an outdated fact" — and the wrong tool for "the user invoked their legal right to be forgotten."
For a single stale fact rather than a whole user, forget is what you want:
diff --git a/apps/docs/versioning.mdx b/apps/docs/versioning.mdx
index a31ca564..0544bbee 100644
--- a/apps/docs/versioning.mdx
+++ b/apps/docs/versioning.mdx
@@ -7,8 +7,6 @@ Supermemory's REST API has two live versions, v3 and v4, and both are current. N
Here's the seam in one program:
-{/* CONFIRM: python — client.add vs client.memories.add naming is inconsistent across published docs; mirrored add-memories.mdx and search.mdx */}
-
```typescript TypeScript
import Supermemory from "supermemory"
@@ -16,7 +14,7 @@ import Supermemory from "supermemory"
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
// hits POST /v3/documents
-await client.memories.add({
+await client.add({
content: "Sarah's being promoted to VP of Product in March",
containerTag: "user_4f8a",
})
@@ -95,12 +93,12 @@ Every document-level and account-level endpoint, all on v3:
| Endpoint | What it does | TS SDK method |
|---|---|---|
-| `POST /v3/documents` | Add a document | `client.memories.add()` |
-| `POST /v3/documents/file` | Upload a file | `client.memories.uploadFile()` |
-| `POST /v3/documents/list` | List documents | `client.memories.list()` |
-| `GET /v3/documents/{id}` | Get a document | `client.memories.get()` |
-| `PATCH /v3/documents/{id}` | Update a document | `client.memories.update()` |
-| `DELETE /v3/documents/{id}` | Delete a document | `client.memories.delete()` |
+| `POST /v3/documents` | Add a document | `client.add()` |
+| `POST /v3/documents/file` | Upload a file | `client.documents.uploadFile()` |
+| `POST /v3/documents/list` | List documents | `client.documents.list()` |
+| `GET /v3/documents/{id}` | Get a document | `client.documents.get()` |
+| `PATCH /v3/documents/{id}` | Update a document | `client.documents.update()` |
+| `DELETE /v3/documents/{id}` | Delete a document | `client.documents.delete()` |
| `DELETE /v3/documents/bulk` | Bulk delete (including by container tag) | raw HTTP |
| `POST /v3/search` | Search document chunks (RAG-style) | `client.search.documents()` |
| `GET` / `PATCH /v3/settings` | Org settings | `client.settings.get()` / `.update()` |
@@ -113,7 +111,7 @@ The documents family also includes batch add, fetch by IDs, chunks, and versions
Two things in this map trip people up, so let's name them:
-**Yes, `client.memories.add()` calls `/v3/documents`.** The SDK is named for the mental model — you add content, supermemory derives memories from it. The route is named for what's actually stored: a document, from which memories are derived. Same operation, two vocabularies. The [glossary](/concepts/glossary) keeps them straight.
+**Yes, `client.add()` calls `/v3/documents`.** The SDK is named for the mental model — you add content, supermemory derives memories from it. The route is named for what's actually stored: a document, from which memories are derived. Same operation, two vocabularies. The [glossary](/concepts/glossary) keeps them straight.
**The SDK covers two of the nine v4 endpoints.** `client.search.memories()` and `client.profile()` are the v4 surface in the TS SDK today. The rest — memory update, forget, forget-matching, list, conversations — are raw HTTP for now. They work fine with `fetch`; they don't have typed wrappers yet.