diff --git a/apps/docs/concepts/architecture.mdx b/apps/docs/concepts/architecture.mdx
index 362f84ed..1fd54f19 100644
--- a/apps/docs/concepts/architecture.mdx
+++ b/apps/docs/concepts/architecture.mdx
@@ -17,10 +17,22 @@ Most memory layers are a vector store that retrieves the nearest chunk. That wor
You can't patch these with a retrieval trick. Fixing them takes extraction that understands time and identity, a graph that revises itself when new information lands, and a store shaped for that data. That's what the rest of this page describes.
-
-
-
-
+{/* TODO(dhravya): drop the architecture disclosure diagram here — ingestion pipeline → data engine → retrieval fan-out. Wrap in when the image lands. */}
+
+```text
+ [documents you ingest]
+ |
+ ingestion pipeline (custom memory model:
+ | extract → relate → derive)
+ +--------+--------+
+ | | |
+memories graph profiles
+ +--------+--------+
+ |
+ hybrid retrieval (semantic + keyword + graph,
+ | fanned out in parallel)
+ your app's context
+```
## What happens when you ingest
@@ -30,7 +42,7 @@ Every document — an API call, a file, a connector item, a chat session — goe
Extraction runs on a custom fine-tuned memory model that we host — not a prompt wrapped around a general-purpose LLM. It's trained on one job: reading raw content and pulling out the facts worth remembering. Each fact carries provenance — where it came from — and time — when it was true. Running our own model is also why ingestion stays cheap at volume — a frontier model doing this work per document would dominate your bill.
-Self-hosted tiers run on-device variants of the same model, at 400M and 2B parameters. See [self-hosting tiers](/self-hosting/tiers) for which variant runs where.
+Self-hosted tiers run on-device variants of the same model, at 400M and 2B parameters. {/* CONFIRM: 400M/2B on-device variant sizes publishable (stated on Lenovo call) */} See [self-hosting tiers](/self-hosting/tiers) for which variant runs where.
### Derivation: Updates, Extends, Derives
@@ -56,7 +68,7 @@ For each [container tag](/concepts/permissioning), the engine maintains a [profi
About five minutes after ingestion, the engine revisits the new memories with the whole graph in view — consolidating related memories and drawing connections that weren't visible while documents were streaming in one at a time. We call it dreaming, because that's roughly the job sleep does for your brain.
-Dreaming is why a container keeps getting better after `done`. If you need fully deterministic post-ingest state, you can disable it via the API.
+Dreaming is why a container keeps getting better after `done`. If you need fully deterministic post-ingest state, you can disable it via the API. {/* CONFIRM: exact param/endpoint for disabling dreaming */}
## Why one store, not three
@@ -74,7 +86,7 @@ A search doesn't pick one index — it fans out to all three in parallel:
2. **Keyword** — exact terms, for the names, IDs, and jargon that embeddings blur.
3. **Graph** — walks relations outward from matched memories, pulling in connected facts the query never mentioned.
-Results merge under a unified score. Because the fan-out runs in parallel inside one store, the graph walk adds about 20ms over a plain vector lookup — connected recall without a second round trip.
+Results merge under a unified score. Because the fan-out runs in parallel inside one store, the graph walk adds about 20ms over a plain vector lookup {/* CONFIRM: ~20ms graph/merge delta — verbal only (Uber/Harmix calls) */} — connected recall without a second round trip.
One call hits all three:
@@ -142,7 +154,7 @@ The query never said "Sarah" — the graph resolved the entity. From here you tu
## Where the milliseconds go
-Numbers you can plan around:
+Numbers you can plan around: {/* CONFIRM: all latency numbers in this table — stated verbally (CBRE call); confirm publishable before ship */}
| Operation | Typical latency |
|---|---|
diff --git a/apps/docs/concepts/customization.mdx b/apps/docs/concepts/customization.mdx
index cc27ebe7..1a7774f7 100644
--- a/apps/docs/concepts/customization.mdx
+++ b/apps/docs/concepts/customization.mdx
@@ -17,7 +17,7 @@ Here's the whole surface at a glance:
| `entityContext` | One container tag | **Who or what the entity is** — grounding for extraction | On `add()`, or `PATCH /v3/container-tags/{tag}` |
| Organization Context | Entire org | The console's no-code editor for `filterPrompt` | console → Settings → Organization Context |
-That third row isn't a separate field. The console's Organization Context panel writes the same `filterPrompt` setting the API does — it's the same lever with a UI on it.
+That third row isn't a separate field. The console's Organization Context panel writes the same `filterPrompt` setting the API does — it's the same lever with a UI on it. {/* CONFIRM: does the console cap Organization Context length? Couldn't find a 750-char (or any) cap in console-v2 code */}
## Set org-wide rules with filterPrompt
@@ -95,7 +95,7 @@ curl -X PATCH https://api.supermemory.ai/v3/container-tags/user_4f8a \
}'
```
-
+{/* CONFIRM: PATCH /v3/container-tags/{tag} is admin-gated in the backend (roleGate ROLE_ADMIN) — confirm which API keys pass that gate before documenting the restriction. */}
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.
@@ -202,7 +202,7 @@ curl -X PATCH https://api.supermemory.ai/v3/settings \
-Use 256–512 when you need precise citations, 1024–2048 for long-form analysis, and `-1` unless you've measured a reason not to.
+Use 256–512 when you need precise citations, 1024–2048 for long-form analysis, and `-1` unless you've measured a reason not to. {/* CONFIRM: recommended ranges — these are editorial guidance, not from code */}
**Connector branding** lets the OAuth screen say "Log in to YourApp" instead of "Log in to Supermemory" by supplying your own client credentials (`googleDriveCustomKeyEnabled` + client ID/secret, and the same pattern for Notion and OneDrive). Setup steps are in the [connectors overview](/connectors/overview).
diff --git a/apps/docs/concepts/how-it-works.mdx b/apps/docs/concepts/how-it-works.mdx
index 8a57383d..0f0941d6 100644
--- a/apps/docs/concepts/how-it-works.mdx
+++ b/apps/docs/concepts/how-it-works.mdx
@@ -50,7 +50,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
-
+{/* CONFIRM: add response shape { id, status } — not covered by SDK-TRUTH */}
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.
@@ -67,7 +67,7 @@ flowchart LR
The canonical status enum is: `unknown → queued → extracting → chunking → embedding → indexing → done | failed`. Any stage can end in `failed`; `unknown` only appears briefly before the document is queued.
-- **extracting** — the content comes out of whatever it was wrapped in: OCR for images, transcription for video, parsing for PDFs and pages.
+- **extracting** — the content comes out of whatever it was wrapped in: OCR for images, transcription for video, parsing for PDFs and pages. {/* CONFIRM: OCR + video transcription as supported extraction paths */}
- **chunking** — the raw content is split into retrieval-sized pieces.
- **embedding** — chunks get vector representations.
- **indexing** — this is where the interesting part happens: our memory model derives memories from the content and wires them into the graph.
@@ -102,7 +102,7 @@ curl "https://api.supermemory.ai/v3/documents/doc_x1k2m9" \
-`done` means one specific thing: **the memories derived from this document are queryable.** Not "stored", not "received" — queryable. Once you see `done`, a search in the same container will find them. Indexing propagates within a couple of seconds.
+`done` means one specific thing: **the memories derived from this document are queryable.** Not "stored", not "received" — queryable. Once you see `done`, a search in the same container will find them. Indexing propagates within a couple of seconds. {/* CONFIRM: eventual consistency ~2s publishable */}
If a document lands in `failed`, the content usually couldn't be extracted — see [errors and limits](/errors-and-limits) for what to check.
@@ -155,7 +155,7 @@ curl -X POST "https://api.supermemory.ai/v4/search" \
}
```
-
+{/* CONFIRM: v4 search result shape ("memory", "similarity") — not covered by SDK-TRUTH */}
## Add a related document, watch memories change
@@ -192,7 +192,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
Three kinds of relations can come out of that comparison:
-
+{/* CONFIRM: relation names (Updates/Extends/Derives), the `isLatest` field name, and "derived memories carry lower confidence" — verify against the graph implementation */}
**Updates** — the new fact supersedes an old one. "Sarah is the design lead" and "Sarah is VP of Product" can't both be current. Supermemory keeps both memories but flips `isLatest`: the old one becomes history, the new one becomes the answer. Search returns the latest version by default, so "what role does Sarah have?" now says VP of Product — and the history is still there if you ask for it. This is how contradictions resolve without losing the timeline.
@@ -208,7 +208,7 @@ This is also why [profiles](/concepts/user-profiles) stay current without you ma
You're not the only one working on this container. About 5 minutes after ingestion, **dreaming** kicks in: a background consolidation pass that revisits recent memories, strengthens connections across documents, and tidies up what the fast path missed. It's the same idea as sleep consolidating your day.
-Dreaming has its own status (`dreaming` / `done`), separate from document processing — a document being `done` doesn't wait on it, and search works fine while it runs. You can disable dreaming through the API if you need fully deterministic ingestion.
+Dreaming has its own status (`dreaming` / `done`), separate from document processing — a document being `done` doesn't wait on it, and search works fine while it runs. You can disable dreaming through the API if you need fully deterministic ingestion. {/* CONFIRM: exact disable param */}
The practical takeaway: recall right after `done` is good; recall a few minutes later can be better connected. Don't benchmark cross-document inference in the first minute after ingestion.
diff --git a/apps/docs/concepts/hybrid-search.mdx b/apps/docs/concepts/hybrid-search.mdx
index 2f7f787f..50b3526f 100644
--- a/apps/docs/concepts/hybrid-search.mdx
+++ b/apps/docs/concepts/hybrid-search.mdx
@@ -399,10 +399,10 @@ Any condition takes `negate: true` to invert it. There's no `!=` operator — fo
There is **no** boolean filter type. Store flags as the strings `"true"`/`"false"` (or `1`/`0` and filter numerically) and match with string equality.
-The limits:
+The limits: {/* CONFIRM: filter limits still true in v4 */}
- Max 200 conditions per query, 8 nesting levels. If you're anywhere near either, your metadata schema wants restructuring — usually into fewer, more meaningful keys.
-- Metadata keys must match `^[a-zA-Z0-9_-]+$` — no spaces, no dots.
+- Metadata keys must match `^[a-zA-Z0-9_-]+$` — no spaces, no dots. {/* CONFIRM: metadata key charset */}
One thing filters are **not** for: tenant isolation. A filter is a query-time convenience; a [container tag](/concepts/permissioning) is a data boundary, enforced by scoped keys. Put the tenant in the container tag, and use metadata for dimensions inside it — channel, agent role, stage.
@@ -438,7 +438,7 @@ If the last turn is too elliptical on its own ("what about the second one?"), re
## Know your latency budget
-What to expect per call, so you can decide which knobs fit inside your budget:
+What to expect per call, so you can decide which knobs fit inside your budget: {/* CONFIRM: latency figures publishable */}
| Configuration | Expectation |
|---|---|
@@ -449,7 +449,7 @@ What to expect per call, so you can decide which knobs fit inside your budget: <
Everything on at once is still well under a second, but in a voice agent or a per-keystroke flow you'll feel it. A pattern that works: defaults on the hot path, `rewriteQuery` + `rerank` on the explicit "search my memory" action where the user expects a beat of thinking.
-One more timing fact: new memories become searchable within a couple of seconds of processing finishing — writes are eventually consistent. Don't write a memory and assert on its retrieval in the same request cycle.
+One more timing fact: new memories become searchable within a couple of seconds of processing finishing — writes are eventually consistent. {/* CONFIRM: ~2s eventual consistency */} Don't write a memory and assert on its retrieval in the same request cycle.
That's the whole tuning surface — two endpoints, five knobs, one query-construction rule. Most setups need exactly one change from the defaults, and now you know which one.
diff --git a/apps/docs/concepts/permissioning.mdx b/apps/docs/concepts/permissioning.mdx
index df7809e9..0e15101f 100644
--- a/apps/docs/concepts/permissioning.mdx
+++ b/apps/docs/concepts/permissioning.mdx
@@ -253,7 +253,7 @@ Because each container maintains its own profile, per-user personalization comes
### One container per client (agencies)
-You run one supermemory organization; each of your clients is a container: `client_hartwell`, `client_meridian`. This is a real data boundary — one client's memories never inform another's — and it makes the commercial mechanics clean: you can meter, report, and delete per client. Container tags have no per-tag cost and big containers carry no performance penalty, so there's no reason to pool clients. Per-client usage breakdown for rebilling: track ingestion per container. If a client gets direct API access, hand them a scoped key for their own container — they can't reach the others even on purpose.
+You run one supermemory organization; each of your clients is a container: `client_hartwell`, `client_meridian`. This is a real data boundary — one client's memories never inform another's — and it makes the commercial mechanics clean: you can meter, report, and delete per client. Container tags have no per-tag cost and big containers carry no performance penalty, so there's no reason to pool clients. Per-client usage breakdown for rebilling: {/* CONFIRM: per-container usage breakdown surface (console or /v3/analytics) */} track ingestion per container. If a client gets direct API access, hand them a scoped key for their own container — they can't reach the others even on purpose.
### Shared org memory + private user memory
@@ -333,7 +333,7 @@ You'll see a plural `containerTags` array on some v3 endpoints — document sear
## Limits and immutability
-- **Capacity:** a container holds up to 10M items , and large containers don't get slower — there's no performance penalty for putting a big tenant in one container. Don't shard a tenant across tags for scale reasons; you'd only be breaking your own boundary.
+- **Capacity:** a container holds up to 10M items {/* CONFIRM: 10M */}, and large containers don't get slower — there's no performance penalty for putting a big tenant in one container. Don't shard a tenant across tags for scale reasons; you'd only be breaking your own boundary.
- **Tags are immutable.** A container tag can't be renamed after creation — the tag string is the container's identity. Decide your naming convention before production data lands. If you end up with two tags that should be one (a migration, or the dual-ID mistake above), consolidate them with the merge endpoint under `/v3/container-tags`.
- **Naming:** ≤100 characters, `^[a-zA-Z0-9_:-]+$`. Spaces, slashes, and `@` are rejected at request time.
@@ -349,7 +349,7 @@ curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \
-d '{ "containerTags": ["user_4f8a"] }'
```
-This removes the user's documents and the memories derived from them . If the user also had a scoped key, revoke it with `DELETE /v3/auth/scoped-key/:id` — revocation is immediate.
+This removes the user's documents and the memories derived from them {/* CONFIRM: derived memories and profile fully cleared by bulk delete */}. If the user also had a scoped key, revoke it with `DELETE /v3/auth/scoped-key/:id` — revocation is immediate.
Deletion is permanent — there's no recovery, so gate this behind your own confirmation flow. And note that deleting documents does **not** restore used quota; you're billed at ingestion, not for storage held.
diff --git a/apps/docs/concepts/surfaces.mdx b/apps/docs/concepts/surfaces.mdx
index 7b0d865d..7b644140 100644
--- a/apps/docs/concepts/surfaces.mdx
+++ b/apps/docs/concepts/surfaces.mdx
@@ -158,7 +158,7 @@ The result is the derived memory, not the raw Notion page:
}
```
-**Out, door two: Claude Desktop, via MCP.** With the [MCP server](/supermemory-mcp/mcp) connected to the same account, asking Claude "what's the plan for the old billing API?" makes it call the search tool against the same store. No re-ingestion, no export — the memory the connector created is the memory MCP finds.
+**Out, door two: Claude Desktop, via MCP.** With the [MCP server](/supermemory-mcp/mcp) connected to the same account, asking Claude "what's the plan for the old billing API?" makes it call the search tool against the same store. No re-ingestion, no export — the memory the connector created is the memory MCP finds. {/* CONFIRM: hosted MCP container-tag scoping — how the MCP session maps to team_billing */}
**Out, door three: your coding agent, via a plugin.** With the [Claude Code plugin](/integrations/claude-code) installed, the hook injects relevant memories when you start working on billing code — so the agent knows about the March 1 sunset before it suggests building against the legacy endpoint. You never asked it to check. That's the point of hooks.
@@ -173,7 +173,7 @@ Two websites, one recurring support question. Here's the map:
| Console | [console.supermemory.ai](https://console.supermemory.ai) | Developers | Create and scope API keys, manage your org and billing, set up connectors, watch usage |
| App | [app.supermemory.ai](https://app.supermemory.ai) | End users | Chat with your memories — the consumer product, which is itself one more door into the engine |
-The console is where every developer workflow starts: **API Keys → Create API Key** gets you the `sm_...` key that the SDK, curl examples, plugins, and SMFS mounts all use. The app can also issue API keys, and plugins accept a key from either surface.
+The console is where every developer workflow starts: **API Keys → Create API Key** gets you the `sm_...` key that the SDK, curl examples, plugins, and SMFS mounts all use. The app can also issue API keys, and plugins accept a key from either surface. {/* CONFIRM: app and console share one login/account */}
The MCP server is the exception on auth: it supports OAuth, so tools like Claude Desktop can connect without you handling a key at all. Under the hood it's still your account, still the same engine.
diff --git a/apps/docs/concepts/user-profiles.mdx b/apps/docs/concepts/user-profiles.mdx
index 7cc0a416..9550284f 100644
--- a/apps/docs/concepts/user-profiles.mdx
+++ b/apps/docs/concepts/user-profiles.mdx
@@ -82,7 +82,7 @@ The two arrays split by how long-lived a fact is, not by topic:
- **`static`** — durable facts: who they are, what they do, standing preferences. This is the stuff that's true next month.
- **`dynamic`** — recent episodes and current state: what they're working on, what happened lately. Entries carry `[Recent]` or `[YYYY-MM-DD]` prefixes so your model can weigh recency; strip them if you only want the text.
-Static populates as the engine sees the same durable facts hold up across ingestions — a brand-new container won't have a settled static section after one message, and early on you'll mostly see dynamic entries. Older dynamic context doesn't pile up forever either: it gets periodically consolidated into denser summaries, so the profile stays compact instead of growing with the container.
+Static populates as the engine sees the same durable facts hold up across ingestions — a brand-new container won't have a settled static section after one message, and early on you'll mostly see dynamic entries. {/* CONFIRM: exact static-population timing/threshold */} Older dynamic context doesn't pile up forever either: it gets periodically consolidated into denser summaries, so the profile stays compact instead of growing with the container.
Beyond the lifespan axis, you can define **buckets** — topical categories like `preferences` or `goals` that a classifier assigns memories to at ingestion time. Every org starts with a built-in `preferences` bucket; you define more in the console, and request them with `include: ["buckets"]` on the profile call. Buckets and `filterPrompt` (your rules for what's worth remembering at all) are the two levers that shape what lands in a profile — bucket descriptions steer where facts get filed, `filterPrompt` steers what gets extracted in the first place. Mechanics for both are in the [profile API reference](/user-profiles) and [Customization](/concepts/customization).
@@ -167,7 +167,7 @@ ${memories ?? ""}
If you're on the Vercel AI SDK, `withSupermemory` does this injection for you — see the [AI SDK integration](/integrations/ai-sdk).
-The profile call is a read — it doesn't count as ingestion, so calling it on every message costs you latency, not quota. It's fast enough to sit in the hot path.
+The profile call is a read — it doesn't count as ingestion, so calling it on every message costs you latency, not quota. It's fast enough to sit in the hot path. {/* CONFIRM: profile latency ~100ms publishable */}
## What profiles are not
diff --git a/apps/docs/connectors/overview.mdx b/apps/docs/connectors/overview.mdx
index a76bbb6a..a4d12166 100644
--- a/apps/docs/connectors/overview.mdx
+++ b/apps/docs/connectors/overview.mdx
@@ -11,7 +11,7 @@ You create a connection, your user completes OAuth (or supplies credentials, for
## What you can connect
-
+{/* CONFIRM: plan matrix — verify per-plan availability against current billing config before publish */}
| Connector | What syncs | Plan | Sync behavior |
|-----------|-----------|------|---------------|
@@ -151,7 +151,7 @@ Every connector has edges. These are the ones that surprise people.
By default, after OAuth your user completes a file-and-folder picker, and **only the items they select** sync. If they pick one folder out of twenty, you sync one folder out of twenty. Users who expect "connect Drive, get Drive" will report missing files — set that expectation in your UI before they hit connect.
-Whole-Drive sync exists: pass `metadata.syncScope: "full"` when you create the connection and the picker is skipped. But broad Drive access runs into Google's rules, not ours. Google treats full-Drive scopes as restricted: consent screens show an unverified-app warning until your OAuth app passes Google's verification, and restricted scopes carry a recurring security assessment per client ID — a cost you own, annually.
+Whole-Drive sync exists: pass `metadata.syncScope: "full"` when you create the connection and the picker is skipped. But broad Drive access runs into Google's rules, not ours. Google treats full-Drive scopes as restricted: consent screens show an unverified-app warning until your OAuth app passes Google's verification, and restricted scopes carry a recurring security assessment per client ID — a cost you own, annually. {/* CONFIRM: Google verification/annual security assessment specifics */}
The production path for whole-Drive sync is a [custom OAuth app](/connectors/google-drive#custom-oauth-application): register your own Google client, complete verification under your brand, then point supermemory at it with `client.settings.update({ googleDriveCustomKeyEnabled: true, ... })`. Your users see your name on the consent screen instead of a warning.
@@ -161,14 +161,14 @@ The production path for whole-Drive sync is a [custom OAuth app](/connectors/goo
- **Granola** has no automatic sync. You trigger imports manually.
- **Web Crawler** recrawls on a schedule, so page edits take time to appear. It respects robots.txt — pages it's told not to fetch won't sync.
- **Notion** connects to one workspace per authorization. To switch accounts, delete the connection and reconnect.
-- **Large files**: connector files over 50MB are skipped.
+- **Large files**: connector files over 50MB are skipped. {/* CONFIRM: 50MB per-file connector limit */}
## What doesn't exist yet
Sources people often ask about that don't sync today:
- **Microsoft Teams, Outlook, and SharePoint** — no connectors today. OneDrive covers files in Microsoft 365, but Teams messages, Outlook mail, and SharePoint sites do **not** sync.
-- **HubSpot** — in development, not shipped.
+- **HubSpot** — in development, not shipped. {/* CONFIRM: HubSpot in development */}
- **Slack, Jira, Confluence, Linear** — not available as connectors.
If your source isn't listed, you don't have to wait. The document API is itself a connector surface: pull from the source's API, add each item with a `customId` (so re-adds update instead of duplicate), and you've built the sync yourself. [Ingestion best practices](/patterns/ingestion) walks through the pattern.
@@ -216,7 +216,7 @@ curl -X DELETE "https://api.supermemory.ai/v3/connections/conn_9f2c1b?deleteDocu
The default delete is permanent — the documents and the memories derived from them are gone, and deletion does **not** restore used quota. If you only need to pause sync, pass `deleteDocuments=false` so the documents stay, then reconnect later.
-The SDK doesn't type `deleteDocuments` as a method parameter — it's a query parameter on the request, which is why the examples pass it through the request options.
+The SDK doesn't type `deleteDocuments` as a method parameter — it's a query parameter on the request, which is why the examples pass it through the request options. {/* CONFIRM: python — extra_query kwarg name against the published pypi package */}
That's the whole surface: connect, verify, disconnect. Everything a connector imports lives in the same engine as your API-added content — one search, one graph, one set of profiles.
diff --git a/apps/docs/connectors/sync-lifecycle.mdx b/apps/docs/connectors/sync-lifecycle.mdx
index f1cdfb99..2d490f86 100644
--- a/apps/docs/connectors/sync-lifecycle.mdx
+++ b/apps/docs/connectors/sync-lifecycle.mdx
@@ -21,10 +21,10 @@ Webhook support varies by provider. Google Drive, Gmail, Notion, and OneDrive pu
GitHub is the one to watch: it syncs on a delay of a few hours, **not** in real time. If you push a commit and search for it a minute later, it won't be there yet. Trigger a [manual sync](#trigger-a-sync-manually) when you need a repo picked up sooner.
-Changes are debounced for about 10 minutes before a sync picks them up. If a user saves a file five times in a row, you get one sync, not five — but it also means even webhook-backed connectors aren't instant.
+Changes are debounced for about 10 minutes before a sync picks them up. If a user saves a file five times in a row, you get one sync, not five — but it also means even webhook-backed connectors aren't instant. {/* CONFIRM: 10-min debounce — verified for S3 in support threads; confirm whether it applies to all providers */}
-Files over 50MB are skipped during sync. They show up as failures in the sync history rather than failing the whole run.
+Files over 50MB are skipped during sync. {/* CONFIRM: 50MB per-file connector limit */} They show up as failures in the sync history rather than failing the whole run.
## Trigger a sync manually
diff --git a/apps/docs/docs.json b/apps/docs/docs.json
index 467d2cd0..48d67aeb 100644
--- a/apps/docs/docs.json
+++ b/apps/docs/docs.json
@@ -386,11 +386,6 @@
"permanent": true,
"source": "/integrations/clawdbot"
},
- {
- "destination": "/overview",
- "permanent": false,
- "source": "/"
- },
{
"destination": "/concepts/how-it-works",
"permanent": true,
diff --git a/apps/docs/errors-and-limits.mdx b/apps/docs/errors-and-limits.mdx
index 61508f32..95608577 100644
--- a/apps/docs/errors-and-limits.mdx
+++ b/apps/docs/errors-and-limits.mdx
@@ -27,7 +27,7 @@ These three get mixed up constantly, and one of them lies to you right now. Here
| `5xx` | Something broke on our side | Retry with backoff; if it persists, tell us |
-A 401 doesn't always mean your key is bad. Right now, running out of quota can also surface as a `401 Unauthorized` — the request gets rejected during auth before billing gets the chance to return a proper 402. We're fixing this. Until then: if a key that worked yesterday suddenly returns 401, [check your usage](#check-your-usage) before you rotate keys or dig through your auth code.
+A 401 doesn't always mean your key is bad. Right now, running out of quota can also surface as a `401 Unauthorized` — the request gets rejected during auth before billing gets the chance to return a proper 402. We're fixing this. Until then: if a key that worked yesterday suddenly returns 401, [check your usage](#check-your-usage) before you rotate keys or dig through your auth code. {/* CONFIRM: quota exhaustion surfacing as 401 — not verifiable in API code; confirm current behavior and fix status */}
The 402 body tells you which meter you exhausted:
@@ -49,7 +49,7 @@ Two limits apply:
The per-key default can be raised. If your workload genuinely needs more than 500 requests a minute on one key, reach out and we'll set a per-key override. But first consider whether you should be batching — [`POST /v3/documents/batch`](/add-memories) turns many adds into one request, and most bursty ingestion workloads fit under the limit once batched.
-Load-testing? You may hit Cloudflare's WAF at the edge before you ever reach the API's rate limiter — blocked requests that never show up in your API logs. That's edge protection, not a supermemory error. Contact us before running a serious load test and we'll make sure your traffic gets through.
+Load-testing? You may hit Cloudflare's WAF at the edge before you ever reach the API's rate limiter — blocked requests that never show up in your API logs. That's edge protection, not a supermemory error. Contact us before running a serious load test and we'll make sure your traffic gets through. {/* CONFIRM: WAF allowlisting process for load tests */}
## Handle 429s with backoff
@@ -168,14 +168,14 @@ Only escalate to exponential delays if you're still getting 429s after honoring
Rate limits reset every minute. Quota doesn't — it's your plan's monthly allowance, and when it runs out you get 402s (or, today, sometimes 401s — see above) until it refreshes or you top up.
-What happens next depends on your plan: on Scale, overage kicks in automatically and you keep going, billed for what you use; on Pro, you top up manually from the console.
+What happens next depends on your plan: on Scale, overage kicks in automatically and you keep going, billed for what you use; on Pro, you top up manually from the console. {/* CONFIRM: overage behavior by plan (Scale auto, Pro manual) */}
Two things to know so quota doesn't surprise you:
- **You're charged on ingestion, not retrieval.** Search is essentially free; the tokens you process when adding content are the cost driver. If you're burning quota faster than expected, look at what you're ingesting, not how often you're searching.
- **Deleting documents does not restore used quota.** The tokens were spent processing the content on the way in. Deleting cleans up your data — it doesn't refund the work.
-The full cost model — what "tokens processed" counts, plan matrices, the cheaper `taskType` lever for retrieval-only ingestion — lives in [usage & billing](/trust/usage-and-billing).
+The full cost model — what "tokens processed" counts, plan matrices, the cheaper `taskType` lever for retrieval-only ingestion {/* CONFIRM: taskType param name */} — lives in [usage & billing](/trust/usage-and-billing).
## Check your usage
diff --git a/apps/docs/overview.mdx b/apps/docs/overview.mdx
index e5ccf348..923ab307 100644
--- a/apps/docs/overview.mdx
+++ b/apps/docs/overview.mdx
@@ -6,7 +6,7 @@ mode: "center"
icon: "book-open"
---
-Supermemory is a context engine. You feed it everything — chat sessions, files, URLs, connector data — and it derives memories, a knowledge graph, and live profiles. When your app needs context, supermemory serves the right slice back in ~300ms.
+Supermemory is a context engine. You feed it everything — chat sessions, files, URLs, connector data — and it derives memories, a knowledge graph, and live profiles. When your app needs context, supermemory serves the right slice back in ~300ms. {/* CONFIRM: publishable latency figure */}
The whole loop is two calls:
@@ -95,6 +95,6 @@ Every surface below is a door into the same engine — one store of memories, on
Most "memory layers" are a vector store that retrieves the nearest chunk. Supermemory understands what it stores: facts carry time, entities connect across sessions, contradictions resolve to what's true *now*, and irrelevant details fade.
-- **State of the art** on LongMemEval and LoCoMo — and [MemoryBench](/memorybench/overview) lets you reproduce the numbers yourself.
-- **Fast enough for the hot path**: profile reads ~100ms, search P50 ~300ms.
+- **State of the art** on LongMemEval and LoCoMo — and [MemoryBench](/memorybench/overview) lets you reproduce the numbers yourself. {/* CONFIRM: exact benchmark figures + ConvoMem */}
+- **Fast enough for the hot path**: profile reads ~100ms, search P50 ~300ms. {/* CONFIRM: publishable latency figures */}
- **Yours to run**: the same engine powers the cloud API, a free local binary, and on-prem enterprise deploys.
diff --git a/apps/docs/patterns/ai-companion.mdx b/apps/docs/patterns/ai-companion.mdx
index 50a101ee..b36a29e2 100644
--- a/apps/docs/patterns/ai-companion.mdx
+++ b/apps/docs/patterns/ai-companion.mdx
@@ -73,7 +73,7 @@ curl -X POST "https://api.supermemory.ai/v3/documents" \
The extraction model reads the full arc of the session and derives memories with real provenance — who said what, when, and how it connects to what it already knows. A few minutes after ingestion, background consolidation ([dreaming](/concepts/how-it-works)) links the new facts into the graph.
-You don't have to wait for the window to close before the session becomes memory. Flush the growing transcript every few turns with the **same** `customId` — the re-add updates that session's document instead of creating a duplicate. That gives you near-live memory during long sessions without turn-by-turn cost.
+You don't have to wait for the window to close before the session becomes memory. Flush the growing transcript every few turns with the **same** `customId` — the re-add updates that session's document instead of creating a duplicate. {/* CONFIRM: re-add with same customId updates the document in place */} That gives you near-live memory during long sessions without turn-by-turn cost.
One session window = one document. Don't be tempted to make it one document per day or per week — a 4-hour window is roughly the span a human would recall as "one conversation," and the extraction quality tracks that intuition.
diff --git a/apps/docs/patterns/company-brain.mdx b/apps/docs/patterns/company-brain.mdx
index b1521af6..67d68815 100644
--- a/apps/docs/patterns/company-brain.mdx
+++ b/apps/docs/patterns/company-brain.mdx
@@ -40,7 +40,7 @@ flowchart LR
sources --> engine --> out
```
-You enable Company Brain for your organization from the supermemory app, connect sources, and invite your team.
+You enable Company Brain for your organization from the supermemory app, connect sources, and invite your team. {/* CONFIRM: enablement flow and plan availability */}
## It's a door, not a separate product
@@ -64,7 +64,7 @@ Container tags are immutable after creation, and splitting one over-broad brain
The non-negotiable rule for shared memory: someone who can't open a document in the source shouldn't be able to get its contents out of the brain. Memory that leaks across access boundaries is worse than no memory.
-The way you enforce this maps directly onto scoping. Content synced from a shared team drive belongs in that team's container. Content from a private or restricted source gets its own container rather than being mixed into a broader one — the container boundary *is* the access boundary, and memories in one container never influence answers from another. For anything programmatic, [scoped API keys](/concepts/permissioning) restrict a key to specific container tags, so the boundary is enforced server-side rather than by whoever wrote the calling code.
+The way you enforce this maps directly onto scoping. Content synced from a shared team drive belongs in that team's container. Content from a private or restricted source gets its own container rather than being mixed into a broader one — the container boundary *is* the access boundary, and memories in one container never influence answers from another. For anything programmatic, [scoped API keys](/concepts/permissioning) restrict a key to specific container tags, so the boundary is enforced server-side rather than by whoever wrote the calling code. {/* CONFIRM: automatic per-user permission inheritance from connector source ACLs */}
One honest limitation to plan around: a container is an all-or-nothing boundary, **not** a per-document ACL. If a source mixes broadly shared and tightly restricted content, don't sync it into one container and hope — split the sync, or leave the restricted part out. [Connector](/connectors/overview) sync scopes let you pick folders rather than syncing everything.
diff --git a/apps/docs/patterns/multi-agent.mdx b/apps/docs/patterns/multi-agent.mdx
index 84a78d77..be8a6450 100644
--- a/apps/docs/patterns/multi-agent.mdx
+++ b/apps/docs/patterns/multi-agent.mdx
@@ -380,7 +380,7 @@ curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \
-
+{/* CONFIRM: deleting a document also removes the memories derived from it — verify before stating explicitly */}
Document deletes are permanent — there's no recovery. Run the list step first and check what matched before you delete, especially with broad filters.
diff --git a/apps/docs/patterns/multi-tenant-saas.mdx b/apps/docs/patterns/multi-tenant-saas.mdx
index 5aaf61ca..c46a37c7 100644
--- a/apps/docs/patterns/multi-tenant-saas.mdx
+++ b/apps/docs/patterns/multi-tenant-saas.mdx
@@ -28,7 +28,7 @@ sequenceDiagram
S->>SM: DELETE /v3/auth/scoped-key/:id
```
-
+{/* CONFIRM: runnable example repo link — spec calls for a linked repo; add once the cookbook example ships */}
## Give every user a container
@@ -303,7 +303,7 @@ curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \
-
+{/* CONFIRM: containerTags on DELETE /v3/documents/bulk is marked deprecated/hidden in the API schema but works and is the planned "reset a user" path — confirm sanctioned status before publish */}
The response confirms how much was removed:
diff --git a/apps/docs/supermemory-mcp/troubleshooting.mdx b/apps/docs/supermemory-mcp/troubleshooting.mdx
index a1191bce..12a2e4f8 100644
--- a/apps/docs/supermemory-mcp/troubleshooting.mdx
+++ b/apps/docs/supermemory-mcp/troubleshooting.mdx
@@ -68,7 +68,7 @@ args = ["-y", "mcp-remote@latest", "https://mcp.supermemory.ai/mcp"]
-
+{/* CONFIRM: Codex config.toml shape (mcp_servers table) against current Codex CLI docs */}
For the screenshot-backed Claude Desktop walkthrough (Settings → Developer → Edit Config, then Connectors), see [Claude Desktop](/supermemory-mcp/claude-desktop). For the one-line CLI install that works across clients, see [Setup and Usage](/supermemory-mcp/setup).
@@ -90,7 +90,7 @@ rm -rf ~/.mcp-auth
npx clear-npx-cache
```
-
+{/* CONFIRM: ~/.mcp-auth as mcp-remote's token cache path; clear-npx-cache as the recommended cache-clearing step */}
Then restart your client and complete the login once. One client, one fresh auth — the loop breaks.
@@ -134,7 +134,7 @@ Supermemory's OAuth server rejects scope strings it doesn't recognize, and some
1. Update the client (or gateway) to its latest version — current versions request scopes correctly.
2. If your config explicitly sets a `scope` value, remove it and let the discovery flow negotiate.
-
+{/* CONFIRM: which scope strings the supermemory OAuth server accepts */}
If neither works — some third-party gateways hardcode their scope request — use [API key auth](#fix-the-re-auth-loop) instead. It bypasses the OAuth handshake completely, scopes and all.
@@ -154,7 +154,7 @@ If the flow completes in the browser ("you can close this window") but the clien
**Symptom:** "My memories are going to the wrong org" — you're a member of multiple organizations, and after connecting via MCP, saved memories show up under your personal org (or a different org) instead of the one you selected in the dashboard.
-This is a known issue: your active organization can get dropped during the MCP OAuth flow, and the session falls back to your default org. Memories saved in that state are in the engine and searchable — they're under the wrong container, not lost.
+This is a known issue: your active organization can get dropped during the MCP OAuth flow, and the session falls back to your default org. {/* CONFIRM: exact fallback behavior when activeOrganizationId is dropped */} Memories saved in that state are in the engine and searchable — they're under the wrong container, not lost.
The deterministic fix is API key auth. API keys are created inside an organization and carry that context with every request — there's no session state to drop:
diff --git a/apps/docs/trust/security.mdx b/apps/docs/trust/security.mdx
index 47020906..20d35bca 100644
--- a/apps/docs/trust/security.mdx
+++ b/apps/docs/trust/security.mdx
@@ -5,7 +5,7 @@ description: "Tenant isolation you can enforce with a key, encryption, SOC 2 Typ
icon: "shield-halved"
---
-This page is written for your security review. It covers the isolation model and how to enforce it, encryption, compliance status (SOC 2 Type 2 , GDPR, HIPAA/BAA), what we do and don't do with your data, and the exact API calls that implement a right-to-erasure request. Where an answer is a document rather than an API call, the [last section](#request-the-reports) tells you how to get it.
+This page is written for your security review. It covers the isolation model and how to enforce it, encryption, compliance status (SOC 2 Type 2 {/* CONFIRM: publishable SOC 2 Type 2 wording */}, GDPR, HIPAA/BAA), what we do and don't do with your data, and the exact API calls that implement a right-to-erasure request. Where an answer is a document rather than an API call, the [last section](#request-the-reports) tells you how to get it.
## The isolation guarantee: scoped API keys
@@ -77,23 +77,23 @@ Human access works the same way: organization members can be restricted to speci
## Encryption in transit and at rest
-Your data is encrypted in transit and at rest.
+Your data is encrypted in transit and at rest. {/* CONFIRM: encryption specifics — TLS version, at-rest cipher (AES-256?), key management details */}
On self-hosted deployments, encryption keys are yours: the enterprise and managed on-prem tiers run inside your infrastructure, so key custody follows your own KMS setup. One gotcha worth knowing before it bites: on self-hosted installs, stored data is encrypted against your configured key — lose or rotate that key incorrectly and existing data becomes unreadable. The setup and recovery notes are in [self-hosting troubleshooting](/self-hosting/troubleshooting).
## Compliance status
-**SOC 2 Type 2.** Supermemory is SOC 2 Type 2 certified. The report is available under NDA — see [how to request it](#request-the-reports).
+**SOC 2 Type 2.** Supermemory is SOC 2 Type 2 certified. {/* CONFIRM: exact publishable statement — "certified" vs "audited/report available", audit period, auditor */} The report is available under NDA — see [how to request it](#request-the-reports).
-**GDPR.** Supermemory supports GDPR-compliant deployments: a Data Processing Agreement (DPA) is available , and the right-to-erasure mechanics are a first-class API operation, [documented below](#delete-a-users-data-the-right-to-erasure-path) — not a support ticket.
+**GDPR.** Supermemory supports GDPR-compliant deployments: a Data Processing Agreement (DPA) is available {/* CONFIRM: DPA availability + whether self-serve or on request */}, and the right-to-erasure mechanics are a first-class API operation, [documented below](#delete-a-users-data-the-right-to-erasure-path) — not a support ticket.
-**HIPAA.** A Business Associate Agreement (BAA) is available on the managed cloud only. The scoping matters, so here's the reasoning: a BAA covers infrastructure *we* operate and audit. On a self-hosted deployment the infrastructure is yours, so there's nothing for us to attest — you inherit your own cloud's compliance posture instead (which is often exactly what a healthcare security team wants; see [deployment tiers](/self-hosting/tiers)).
+**HIPAA.** A Business Associate Agreement (BAA) is available on the managed cloud only. {/* CONFIRM: BAA availability + cloud-only scope */} The scoping matters, so here's the reasoning: a BAA covers infrastructure *we* operate and audit. On a self-hosted deployment the infrastructure is yours, so there's nothing for us to attest — you inherit your own cloud's compliance posture instead (which is often exactly what a healthcare security team wants; see [deployment tiers](/self-hosting/tiers)).
If you're evaluating for a regulated environment, the practical split is: managed cloud when you want our controls and paperwork to cover you, self-hosted when your controls must cover everything.
## Your data is not training data
-We don't train models on your data.
+We don't train models on your data. {/* CONFIRM: exact scope of no-training commitment — all customers or paid plans only; contractual wording */}
Worth understanding *how* that's true mechanically, because it's a common source of skepticism. Supermemory's ingestion pipeline runs a custom fine-tuned memory model — but fine-tuning happened before your data ever arrived. When you ingest content, the model derives memories from it at inference time; nothing about your content updates model weights. The derived state (memories, graph, [profiles](/concepts/user-profiles)) lives inside your container as data, not inside any model — which is also why deleting a container [actually removes what was learned from it](#delete-a-users-data-the-right-to-erasure-path).
@@ -101,7 +101,7 @@ Worth understanding *how* that's true mechanically, because it's a common source
Data residency comes in four shapes, from most managed to most yours:
-- **Managed cloud** — the default.
+- **Managed cloud** — the default. {/* CONFIRM: cloud hosting region(s) and whether region pinning / EU residency is available */}
- **Managed on-prem** — we operate supermemory inside your cloud account; data never leaves your VPC.
- **Enterprise self-hosted** — you run everything, including on air-gapped infrastructure.
- **Local binary** — for development and small workloads, entirely on your machine.
@@ -148,7 +148,7 @@ curl -X DELETE "https://api.supermemory.ai/v3/documents/bulk" \
-This removes the user's documents and the memories derived from them. If the user held a scoped key, revoke it too: `DELETE /v3/auth/scoped-key/:keyId` takes effect immediately.
+This removes the user's documents and the memories derived from them. {/* CONFIRM: derived memories, graph edges, and profile fully cleared by bulk delete; backup/retention window before data is unrecoverable */} If the user held a scoped key, revoke it too: `DELETE /v3/auth/scoped-key/:keyId` takes effect immediately.
Deletion is permanent and there's no recovery — gate this behind your own confirmation flow. Note that deleting documents does **not** restore used quota: you're billed at ingestion, not for storage held. See [usage & billing](/trust/usage-and-billing).
@@ -214,7 +214,7 @@ And `forget-matching` handles "forget everything about X" agentically, with a `d
## Request the reports
-For anything that's a document rather than an API call — the SOC 2 report, the DPA, a BAA, or answers to a security questionnaire — reach the team through your account contact, or at the address on [console.supermemory.ai](https://console.supermemory.ai). The SOC 2 report ships under NDA; the DPA and BAA come back countersigned.
+For anything that's a document rather than an API call — the SOC 2 report, the DPA, a BAA, or answers to a security questionnaire — reach the team through your account contact, or at the address on [console.supermemory.ai](https://console.supermemory.ai). {/* CONFIRM: security/report-request contact address (security@supermemory.ai?) */} The SOC 2 report ships under NDA; the DPA and BAA come back countersigned.
---
diff --git a/apps/docs/trust/usage-and-billing.mdx b/apps/docs/trust/usage-and-billing.mdx
index d47de6a5..d1009a06 100644
--- a/apps/docs/trust/usage-and-billing.mdx
+++ b/apps/docs/trust/usage-and-billing.mdx
@@ -48,9 +48,9 @@ You get back each meter with its usage and limit, plus your current billing peri
}
```
-
+{/* CONFIRM: billing usage response shape and exact meter names */}
-One thing to know up front: scoped API keys can **not** read billing endpoints — they return a 403. Use an unscoped key, or check the billing page in the console instead.
+One thing to know up front: scoped API keys can **not** read billing endpoints — they return a 403. Use an unscoped key, or check the billing page in the console instead. {/* CONFIRM: scoped-key 403 on billing endpoints */}
## What "tokens processed" counts
@@ -61,22 +61,22 @@ Two meters exist:
- **Text tokens** — plain text, tweets, markdown.
- **Rich content tokens** — PDFs, images, files, web pages. Anything that needs extraction before it's text.
-Rich content costs more per token than plain text, because extraction does more work. If you can send markdown instead of a PDF of the same content, send markdown — it's also what the [ingestion guide](/patterns/ingestion) recommends for quality reasons.
+Rich content costs more per token than plain text, because extraction does more work. {/* CONFIRM: text vs rich meter split and relative pricing */} If you can send markdown instead of a PDF of the same content, send markdown — it's also what the [ingestion guide](/patterns/ingestion) recommends for quality reasons.
-Updates are billed on the **delta**. When you update a document (or re-add one with the same `customId`), you're charged only for the token count *increase* over what that document already cost. Re-processing unchanged content bills zero. So appending a session to an existing conversation document charges you for the new turns, not the whole history again — this is why [ingesting full conversations under one `customId`](/patterns/ingestion) is cheaper than adding every turn as its own document.
+Updates are billed on the **delta**. When you update a document (or re-add one with the same `customId`), you're charged only for the token count *increase* over what that document already cost. Re-processing unchanged content bills zero. So appending a session to an existing conversation document charges you for the new turns, not the whole history again — this is why [ingesting full conversations under one `customId`](/patterns/ingestion) is cheaper than adding every turn as its own document. {/* CONFIRM: delta billing on updates and customId re-adds */}
And the reads are not on this meter at all:
- **Search** is metered per query, not per token — and priced low enough that it's effectively free at any realistic volume. Ingestion is where your money goes.
- **Profile reads** don't consume tokens. A `client.profile({ containerTag })` call isn't metered; add a `q` and it counts as one search query.
-- **Memory injection** — the AI SDK wrapper putting a profile or search results into your prompt — is a profile/search read under the hood, so it follows the same rules. It never consumes ingestion tokens.
+- **Memory injection** — the AI SDK wrapper putting a profile or search results into your prompt — is a profile/search read under the hood, so it follows the same rules. It never consumes ingestion tokens. {/* CONFIRM: injection billing — verified in code (read paths only hit the search-query meter), confirm this is the publishable statement */}
- **Storage is free.** A document you ingested in January costs nothing to keep in July.
## Deleting documents does not restore quota
The meter counts processing, and the processing already happened. Deleting a document removes its content, chunks, and derived memories — but the tokens it consumed stay consumed. Your quota is a record of work done, not a measure of what's currently stored.
-Your quota refreshes at the start of each billing period. Unused quota doesn't roll over.
+Your quota refreshes at the start of each billing period. Unused quota doesn't roll over. {/* CONFIRM: monthly refresh cadence + no-rollover on all plans */}
If you're near the limit, deleting old documents won't buy you headroom — upgrading or waiting for the reset will.
@@ -91,7 +91,7 @@ The mental math is short:
## Cut costs with `taskType: "superrag"`
-If a set of documents only needs to be searchable — you'll never want derived memories, a graph, or profile contributions from it — ingest it with `taskType: "superrag"`. That runs the retrieval-only pipeline (extract, chunk, embed) and skips memory derivation, at about 5x cheaper per token than the default `"memory"` task type.
+If a set of documents only needs to be searchable — you'll never want derived memories, a graph, or profile contributions from it — ingest it with `taskType: "superrag"`. That runs the retrieval-only pipeline (extract, chunk, embed) and skips memory derivation, at about 5x cheaper per token than the default `"memory"` task type. {/* CONFIRM: taskType param name and "superrag"/"memory" values */}
A support-docs corpus is the typical case:
@@ -200,7 +200,7 @@ Each entry in `byKey` carries the token total for that key:
}
```
-The endpoint also accepts `from`/`to` (ISO 8601) instead of `period`, and paginates with `page` and `limit`. The same family has `/v3/analytics/errors` and `/v3/analytics/logs` for error breakdowns and request-level logs.
+The endpoint also accepts `from`/`to` (ISO 8601) instead of `period`, and paginates with `page` and `limit`. {/* CONFIRM: analytics usage response fields and query params */} The same family has `/v3/analytics/errors` and `/v3/analytics/logs` for error breakdowns and request-level logs.
## Handle running out
@@ -213,15 +213,15 @@ When a meter is exhausted, writes start returning `402` with a body that names t
}
```
-
+{/* CONFIRM: 402 status and exact body shape */}
-Catch the `402` in your ingestion path and queue the writes — reads keep working, so your app degrades to "remembers everything up to now" rather than breaking. Whether usage past the included quota bills as overage or hard-blocks depends on your plan and its overage setting.
+Catch the `402` in your ingestion path and queue the writes — reads keep working, so your app degrades to "remembers everything up to now" rather than breaking. Whether usage past the included quota bills as overage or hard-blocks depends on your plan and its overage setting. {/* CONFIRM: overage defaults and availability by plan */}
## Manage invoices, downgrades, and cancellation
-Invoices, payment methods, plan changes, and cancellation all live in the console's billing settings. Only org admins can manage billing.
+Invoices, payment methods, plan changes, and cancellation all live in the console's billing settings. {/* CONFIRM: exact console navigation path */} Only org admins can manage billing.
-When you downgrade or cancel, your data is not deleted — you keep read access, and ingestion is governed by the lower plan's quota from the next billing period.
+When you downgrade or cancel, your data is not deleted — you keep read access, and ingestion is governed by the lower plan's quota from the next billing period. {/* CONFIRM: plan-downgrade data behavior — verify data retention and any limits enforcement on existing over-quota data */}
That's the whole meter: pay when supermemory processes, read for ~free, and delete for hygiene — not refunds.