diff --git a/apps/docs/agents-and-mcp.mdx b/apps/docs/agents-and-mcp.mdx
index 4a1a4290..13f3f78d 100644
--- a/apps/docs/agents-and-mcp.mdx
+++ b/apps/docs/agents-and-mcp.mdx
@@ -28,7 +28,6 @@ Useful for coding agents:
```bash
npx supermemory setup # detect project, launch/print integration flow
npx supermemory setup --prompt # print integration prompt only
-npx supermemory setup --json # machine-readable output
npx supermemory help --json # agent-readable command catalog
npx supermemory help --all
npx supermemory migrate # move a v3/v4 project to v5 with your agent
@@ -210,7 +209,7 @@ DO NOT USE — deprecated, undocumented, or fabricated:
- Endpoints: /v1/anything, /v3/documents, /v3/search, /v4/search, /v4/profile, /v4/memories (use /ns/{namespace}/...)
- Headers: x-supermemory-api-key, x-api-key, x-sm-user-id (for API auth)
- Body keys: containerTag, containerTags, customId (use `id`), entityContext (use `supportingContext`), filterByMetadata (use `group`), documentDate (use `date`), q (use `query`), filters (use `filter`), userId, spaces
-- SDK: `client.add({ containerTag })`, `client.search.execute`, `client.memories.*`, `client.profile({ q })`
+- SDK: `client.add({ containerTag })`, `client.search.execute`, `client.memories.add` / `client.memories.updateMemory`, `client.profile({ q })`
SCOPING IS LOAD-BEARING. Every write and every search MUST name one namespace in the path.
diff --git a/apps/docs/authentication.mdx b/apps/docs/authentication.mdx
index 9c90b9c6..70315a74 100644
--- a/apps/docs/authentication.mdx
+++ b/apps/docs/authentication.mdx
@@ -50,11 +50,15 @@ This works for Google Drive, Notion, and OneDrive. See the full setup in [Custom
## Scoped API keys
-Scoped keys are restricted to one namespace (what v3/v4 called a container tag). They can only access documents and search within that namespace — use them to give a client, session, or tenant limited access without shipping your org master key.
+Scoped keys are restricted to one namespace (what v3/v4 called a container tag), or to a fixed list of namespaces. They can read and write content only inside those namespaces, subject to the key's read/write permission and member restrictions — use them to give a client, session, or tenant limited access without shipping your org master key.
+
+
+Namespace scoping is not read-only access. Writable scoped keys can update and delete documents and forget memories. Deleting or moving a namespace additionally requires an org admin or owner with write access to the source and, for moves, the destination.
+
Pairs with [namespaces](/concepts/container-tags) for multi-tenant isolation.
-**Allowed endpoints:** `/v3/documents`, `/v3/memories`, `/v4/memories`, `/v3/search`, `/v4/search`, `/v4/profile`
+**Allowed endpoints:** `/ns/{namespace}/document`, `/ns/{namespace}/list`, `/ns/{namespace}/search`, `/ns/{namespace}/profile`, and `/ns/{namespace}/memories`; `/namespaces` and `/ns/{namespace}`; and the legacy `/v3/documents`, `/v3/memories`, `/v4/memories`, `/v4/conversations`, `/v3/search`, `/v4/search`, `/v4/profile`, `/v3/container-tags/list`, and `/v3/session` routes. Any other route returns `403`.
Scoped keys **cannot** read billing, manage org settings, or mint further keys.
@@ -78,7 +82,8 @@ curl https://api.supermemory.ai/v3/auth/scoped-key \
| Parameter | Required | Default | Description |
| --- | --- | --- | --- |
-| `containerTag` | Yes | — | The namespace to scope the key to. Alphanumeric, hyphens, underscores, colons, dots |
+| `containerTag` | Yes, unless `containerTags` is set | — | The namespace to scope the key to. Up to 100 characters: letters, numbers, hyphens, underscores, colons |
+| `containerTags` | No | — | Scope the key to several namespaces instead of one. Takes precedence over `containerTag` |
| `name` | No | `scoped_{containerTag}` | Display name for the key |
| `expiresInDays` | No | — | 1–365 days |
| `rateLimitMax` | No | `500` | Max requests per window (1–10,000) |
@@ -92,8 +97,9 @@ curl https://api.supermemory.ai/v3/auth/scoped-key \
"id": "key-id",
"name": "scoped_my-project",
"containerTag": "my-project",
+ "containerTags": ["my-project"],
"expiresAt": "2026-03-08T00:00:00.000Z",
- "allowedEndpoints": ["/v3/documents", "/v3/memories", "/v4/memories", "/v3/search", "/v4/search", "/v4/profile"]
+ "allowedEndpoints": ["/v3/session", "/v3/documents", "/v3/memories", "/v4/memories", "/v4/conversations", "/ns/*/memories", "/v3/search", "/v4/search", "/v4/profile", "/v3/container-tags/list", "/ns/*/document", "/ns/*/list", "/ns/*/search", "/ns/*/profile", "/namespaces$", "/ns$", "/ns/*$"]
}
```
@@ -111,4 +117,4 @@ curl https://api.supermemory.ai/v3/auth/scoped-key/KEY_ID \
```json
{ "success": true }
-```
\ No newline at end of file
+```
diff --git a/apps/docs/concepts/container-tags.mdx b/apps/docs/concepts/container-tags.mdx
index f555cbd8..e5e3cf72 100644
--- a/apps/docs/concepts/container-tags.mdx
+++ b/apps/docs/concepts/container-tags.mdx
@@ -97,7 +97,7 @@ The colon is intentionally allowed so you can build **hierarchical** namespaces
## Scope lives in the URL
-In v5 the namespace is a path segment, not a body field. Every scoped endpoint starts with `/ns/{namespace}/`, and every SDK call takes `namespace` as a top-level key next to `body`.
+In v5 the namespace is a path segment, not a body field. Every scoped endpoint starts with `/ns/{namespace}/`, and every scoped SDK call takes `namespace` as its first argument.
| Legacy (v3/v4) | v5 |
|-----------|------|
@@ -138,8 +138,8 @@ await supermemory.list("project_q1", "documents");
Namespaces are also an **authorization boundary**, not just an organizational one. Two mechanisms can restrict which namespaces a given caller may touch:
-- **API key scopes** — an API key can be limited to a specific set of namespaces, with read or write permission per namespace.
-- **Member restrictions** — an organization member can be granted access to only certain namespaces.
+- **API key scopes** — an API key can be limited to a specific set of namespaces, and a key can be read-only.
+- **Member restrictions** — an organization member can be granted access to only certain namespaces, with read or write permission per namespace.
When a request is restricted, Supermemory validates the namespace in the URL against the caller's allowed set:
@@ -159,11 +159,13 @@ The `namespaces.*` SDK methods read and change a namespace itself, as opposed to
| `supermemory.namespaces.list()` | Page through namespaces with `documentCount` and `memoryCount`. |
| `supermemory.namespaces.get(namespace)` | Read one namespace and its `supportingContext`. |
| `supermemory.namespaces.update(namespace, { supportingContext })` | Set a context prompt applied when processing documents in this namespace. Useful for steering extraction per project or tenant. |
-| `supermemory.namespaces.delete(namespace)` | Delete the namespace and all its documents and memories. |
+| `supermemory.namespaces.delete(namespace)` | Delete the namespace, its namespace-owned memory records, and documents exclusive to it. Shared documents are retained. |
| `supermemory.namespaces.delete(namespace, { moveTo })` | Move the content into another namespace, then remove this one. Queued; returns an `operationId`. |
`supportingContext` is what v3/v4 called `entityContext`. The legacy "merge" operation is now a delete with `moveTo`, one source namespace per request.
+Namespace deletion and moves require an org admin or owner with write access to the source namespace; moves also require write access to the destination. The default `sm_project_default` namespace cannot be permanently deleted. See [deletion scope and erasure limits](/overview/security).
+
```typescript TypeScript
@@ -178,7 +180,7 @@ const { namespaces, pagination } = await supermemory.namespaces.list();
await supermemory.namespaces.delete("project_research_old", {
moveTo: "project_research",
});
-// { success, status: "queued", operationId, namespace, moveTo }
+// { status: "queued", operationId, namespace, moveTo }
```
```bash curl
@@ -190,10 +192,8 @@ curl -X PATCH "https://api.supermemory.ai/ns/project_research" \
curl "https://api.supermemory.ai/namespaces" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
-curl -X DELETE "https://api.supermemory.ai/ns/project_research_old" \
- -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{ "moveTo": "project_research" }'
+curl -X DELETE "https://api.supermemory.ai/ns/project_research_old?moveTo=project_research" \
+ -H "Authorization: Bearer $SUPERMEMORY_API_KEY"
```
diff --git a/apps/docs/snippets/api-v5-organization.mdx b/apps/docs/snippets/api-v5-organization.mdx
index 765073bb..608a2050 100644
--- a/apps/docs/snippets/api-v5-organization.mdx
+++ b/apps/docs/snippets/api-v5-organization.mdx
@@ -69,6 +69,6 @@ await supermemory.organization.update({
- Compare the v5 context with the legacy `filterPrompt` before cutover.
- Set, replace, and clear organizational context.
-- Confirm `namespaceCount` agrees with `pagination.totalItems` from `GET /namespaces` for the same credentials.
+- Confirm `namespaceCount` agrees with `pagination.totalItems` from `GET /namespaces` when called with an unrestricted org key. `namespaceCount` always counts every namespace in the organization, while `GET /namespaces` only counts the namespaces the caller can read.
- Verify non-admin callers receive `403` on PATCH.
- Confirm removed fields are not required by downstream configuration code.
diff --git a/apps/docs/snippets/api-v5-overview.mdx b/apps/docs/snippets/api-v5-overview.mdx
index fbea7e63..a63c3709 100644
--- a/apps/docs/snippets/api-v5-overview.mdx
+++ b/apps/docs/snippets/api-v5-overview.mdx
@@ -6,7 +6,7 @@
The API base URL and bearer keys do not change.
-**Where parameters live:** `GET` options go in the query string. `POST`, `PATCH`, and `PUT` options go in the JSON body, or as form fields on file uploads; the one exception is list pagination (`page`, `limit`, `sort`, `order`), which stays in the query string. `DELETE` options such as `moveTo` go in the query string, while bulk deletes send their `ids` in the JSON body. Routes reject options sent in the wrong place with `400`. v5 application routes are unversioned; [`/v5/reference`](https://api.supermemory.ai/v5/reference) is the interactive v5 reference, not an API path prefix.
+**Where parameters live:** `GET` options go in the query string. `POST`, `PATCH`, and `PUT` options go in the JSON body, or as form fields on file uploads; the one exception is list pagination (`page`, `limit`, `sort`, `order`), which stays in the query string. `DELETE` options such as `moveTo` go in the query string, while bulk deletes send their `ids` in the JSON body. Most routes reject options sent in the wrong place with `400`. `DELETE /ns/{namespace}` does not: it ignores a JSON body, so a `moveTo` sent in the body permanently deletes the namespace instead of moving it. v5 application routes are unversioned; [`/v5/reference`](https://api.supermemory.ai/v5/reference) is the interactive v5 reference, not an API path prefix.
## Recommended migration process
@@ -55,7 +55,7 @@ await supermemory.add("user_1", { content: "new turn" })
```
-Every v5 call takes one object. `namespace`, path IDs, and query parameters are top-level keys; the JSON body goes under `body`. Legacy `containerTag` never appears in a body again. There is no v5 Python SDK yet.
+URL values are positional (`namespace` first, then `id` where there is one); everything else goes in one object. Legacy `containerTag` never appears in a body again. The Python SDK speaks v5 from 5.0.0 with the same shape and keyword arguments: `client.add("user_1", content="new turn")`.
## Endpoint map
diff --git a/apps/docs/snippets/api-v5-sdks.mdx b/apps/docs/snippets/api-v5-sdks.mdx
index 1a2ae281..80dd71b3 100644
--- a/apps/docs/snippets/api-v5-sdks.mdx
+++ b/apps/docs/snippets/api-v5-sdks.mdx
@@ -1,4 +1,4 @@
-Check which client you call the API through before you translate requests. Both official SDKs speak v5; the integration packages do not yet.
+Check which client you call the API through before you translate requests. Both official SDKs and `@supermemory/tools` 3.x speak v5; check the table before upgrading anything else.
| Client | v5 support | What to do |
| --- | --- | --- |
diff --git a/apps/docs/v5/api-reference/overview.mdx b/apps/docs/v5/api-reference/overview.mdx
index bd6b9bee..981df7f6 100644
--- a/apps/docs/v5/api-reference/overview.mdx
+++ b/apps/docs/v5/api-reference/overview.mdx
@@ -36,7 +36,7 @@ import { Supermemory } from "supermemory"
const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
```
-Every SDK call takes one object. `namespace`, path IDs, and query parameters are top-level keys; the JSON body goes under `body`. Each reference page below shows the SDK call next to the equivalent `curl`. There is no v5 Python SDK yet.
+URL values are positional arguments (`namespace` first, then `id` where there is one), and everything else goes in one object: `supermemory.add("user_123", { content })`. Each reference page below shows the SDK call next to the equivalent `curl`. The Python SDK (`pip install supermemory`, 5.0.0 and later) follows the same shape with keyword arguments: `client.add("user_123", content="...")`.