Skip to main content

Migrate with an agent

Paste this into Claude Code, Cursor, or Codex. It fetches this guide as markdown and rewrites every legacy call.

Migrate by hand

This is a breaking API migration. Do not change only the URL: fields moved, search defaults changed, response envelopes changed, and some legacy operations have no v5 replacement.
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 is the interactive v5 reference, not an API path prefix.
1

Inventory every legacy call

Search for /v3/, /v4/, containerTag, containerTags, customId, entityContext, filterByMetadata, filters, and legacy SDK methods such as client.search.execute, client.profile, and client.connections.*.
2

Resolve one namespace per request

Move the legacy containerTag into /ns/{namespace}. Never infer scope from a document or memory ID, and never send multiple namespaces to one v5 request.
3

Translate requests by domain

4

Update response readers

Migrate envelopes, includes, pagination, profile buckets, system fields, and partial-error handling before switching traffic.
5

Verify legacy and v5 side by side

Follow the verification and rollout guide. Compare identity and behavior—not raw JSON ordering—and set changed defaults explicitly during rollout.
6

Cut over one domain at a time

Switch traffic, monitor failures and semantic drift, then remove legacy compatibility code only after that domain passes verification.

Upgrade the SDK

The v5 TypeScript SDK ships as the same supermemory package. Install it, then replace the legacy client:
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.

Endpoint map

Connectors

Connector routes also move under the namespace. Legacy containerTags arrays become one namespace per connector.
authorization is null for config providers (web-crawler, s3, granola), which start syncing immediately. connectors.sync returns { id, status: "queued" } and 409 when a sync is already running.

SDKs, tools and the CLI

Check which client you call the API through before you translate requests. Both official SDKs speak v5; the integration packages do not yet.

TypeScript SDK changes

The v5 SDK scopes every content call to one namespace, passed first. URL values (namespace, then id where there is one) are positional; everything else goes in one object:
If your code passes a containerTags array, pick one namespace. A v5 document lives in exactly one namespace, so there is no multi-tag write to translate. Code that read across several tags runs one call per namespace and merges the results.
Some v4 methods are gone from the v5 SDK. Most have a v5 way to do the same thing: Gone with no replacement: settings.reset, settings.suggestBuckets, documents.fileUrl, and the reason field on forget. The full method map is in the SDK’s migration guide.

Document ingestion

v5 moves document scope into the URL and keeps repeated caller IDs attached to one evolving document.

Rename common fields

Add or append one document

The response remains an acceptance result with id and status. Its status is the document’s processing state after the request: queued when new work was queued, otherwise the document’s current state (for example done for an unchanged duplicate, or failed for a metadata-only update to a failed document). Possible values: unknown, queued, extracting, chunking, embedding, indexing, done, failed. Repeating the v5 request with id: "conv_1" adds or diffs the new content into that document; it does not silently replace the canonical source.

Batch ingestion

Send the v5 body to POST /ns/user_1/document/batch. The array accepts 1–600 document objects. taskType and dreaming sit at the top level of the body, next to documents, and apply to every item; document content, ID, context, metadata, grouping, and date stay per item. results lists accepted documents first, in request order, then failed ones; match each result by id, or by url for a failed item with no ID. Inspect count (accepted), failed, and every item in results; each item’s status is the document’s processing state (unknown, queued, extracting, chunking, embedding, indexing, done, or failed), or error when that item failed, and a batch can contain successful and failed items together.

File ingestion

Replace POST /v3/documents/file with POST /ns/{namespace}/document/file. Continue using multipart/form-data: The API acknowledges the file after durable acceptance, with status set as for a JSON add. Extraction, indexing, and memory formation continue asynchronously; poll the document rather than assuming the first response means processing is complete.

Processing choices

  • taskType: "memory" extracts long-term memories; taskType: "superrag" indexes source context without memory generation.
  • dreaming: "dynamic" (default) groups related documents into coherent memory units.
  • dreaming: "instant" processes each document independently and bills one extra operation per document.
  • Memories appear quickly only with dreaming: "instant". Under dynamic, a fresh namespace can show zero memories and an empty profile for several minutes. Use instant for quickstarts and parity tests.
These options go in the JSON body (or as form fields for file routes). Ingest routes take no query parameters; sending one returns 400.

With the SDK

The namespace is the first argument on every call. taskType and dreaming sit next to content in the same object. uploadFile is multipart, so metadata is a JSON string there, not an object.

Verification

  • Ingest text, a public URL, and a file, then wait for each document to finish processing.
  • Repeat a caller-defined ID and confirm append/diff behavior instead of replacement.
  • Submit a mixed-success batch and verify each result matches its document by ID, with per-item errors.
  • Confirm metadata and grouping remain filterable after processing.

Document updates

v5 makes the difference between adding new information and replacing the canonical source explicit.

Choose the correct write

Update text or URL content

The v5 body accepts any non-empty subset of content, supportingContext, metadata, group, or date, plus optional taskType and dreaming (which alone do not count as a change). Supplying content makes it the new canonical source; facts supported only by the previous source can disappear after reprocessing.

Replace a file-backed document

POST requires file and replaces the canonical source plus user-controlled metadata, grouping, context, and date. Omitted supporting fields are cleared. Use it when the submitted request is the complete new representation of the file-backed document.

Partially update a file-backed document

PATCH changes only supplied fields. Include file to replace the source while retaining omitted supporting fields, or omit file for metadata-, group-, context-, or date-only changes. metadata and group are JSON-encoded strings; supportingContext and date are plain strings.
There is no public v5 PUT /ns/{namespace}/document/file/{id} operation. Use POST for a complete replacement and PATCH for a partial update.

With the SDK

replaceWithFile is the POST full replacement and requires file. updateFile is the PATCH partial update; file is optional and metadata merges key by key.

IDs and scope

The path id may be the Supermemory document ID or your caller-defined ID. It is resolved only inside {namespace}; an ID from another namespace is not a cross-namespace update mechanism.

Processing and conflicts

Content or file replacement is accepted before downstream processing completes. A document still processing, a namespace conflict, or a conflicting internal file path can return 409; retry only after the conflicting operation reaches a terminal state.

Verification

  • Patch metadata alone and confirm document content and derived facts remain intact.
  • Patch content and confirm the new source is canonical after processing.
  • Replace a file with POST and confirm omitted user metadata is cleared.
  • Patch a file-backed document and confirm omitted fields remain unchanged.
  • Attempt the same ID in another namespace and confirm the update is rejected or not found.

Content management

v5 retrieves, lists, and removes content within one explicit namespace.

Retrieve a document and its derived context

Pass include as a comma-separated list to return chunks, memories, or both. Keys you omit are absent; requested keys with no results are empty arrays. Lifecycle fields move under system:
system.status is one of unknown, queued, extracting, chunking, embedding, indexing, done, or failed.

Retrieve a memory and its history

v5
Returns one memory with id, memory, metadata, isStatic, isInference, isLatest, isForgotten, version, and system.createdAt/updatedAt. A memory from another namespace returns 404; a forgotten memory, or one past its forget_after, is still returned with isForgotten: true.
  • include=related adds included.related.parents (earlier versions), children (newer versions), and siblings (memories connected by extends or derives). Each list walks outward from the memory until it holds relatedLimit items (default 10, maximum 100). Forgotten memories and memories in other namespaces are left out.
  • include=documents adds included.document, the most recently updated source document. With both values, every related memory also carries its own document.

List documents, chunks, or memories

Set type to documents, chunks, or memories. Pagination and sorting move to the query string as plain integers and values; the body takes an optional filter and, for memories, include. Defaults are page=1, limit=10 (maximum 100), sort=createdAt, and order=desc. Memory lists hide forgotten memories and memories past their forget_after. Send "include": {"forgotten": true} to list them too; they come back with isForgotten: true. Document memories (include=memories on GET /ns/{namespace}/document/{id}) report the same flag. Every response contains documents, chunks, memories, and pagination. Only the selected resource array is populated. Replace legacy memories assumptions in document-list callers with documents.

Delete documents

The v5 array accepts 1–100 Supermemory or caller-defined IDs. Inspect both count and per-ID errors; HTTP success can include partial failures.

With the SDK

There is no separate processing list. Read system.status on each item returned by supermemory.list(namespace, "documents"). Chunks come from supermemory.list(namespace, "chunks") or documents.get with include: ["chunks"].

Forget memories

Both return { count, matches, errors }. For drift-free semantic deletion, preview with dryRun: true, review the IDs, then submit them to the exact-ID endpoint. See memory forgetting for the complete dry-run, approval, response, and audit workflow.

Verification

  • Assert requested empty includes are [], while omitted includes are absent.
  • Paginate each resource type until currentPage >= totalPages; unselected arrays stay empty.
  • Verify chunk rows contain their parent documentId.
  • Exercise partial document-delete failures and semantic dry runs.
  • Verify IDs cannot read, list, or delete content outside their namespace.
v5 searches one namespace, defaults to hybrid recall, and takes every option in one typed JSON body. Search has no query-string parameters.

Request mapping

With the SDK

query, searchMode, limit, threshold, filter, include, rerank, and rewriteQuery all go in one object (the JSON body over HTTP). Omitting searchMode gives hybrid.

Changed defaults

Set mode and threshold explicitly while comparing versions. After parity testing, remove them only if you want the broader v5 hybrid defaults.

Search modes

Legacy include.chunks has no v5 equivalent. Choose chunks or hybrid instead.

Included context and ranking

include is an object of booleans in the body, e.g. "include": {"documents": true, "related": true}. Each flag defaults to false.
  • include.documents adds the most relevant source document to each result.
  • include.related adds parent, child, and sibling memories. Related memories come only from the same namespace and must match the request’s filter, so they never surface content the search itself would exclude.
  • include.forgotten lets forgotten and expired memories appear in results, including as primary results.
  • rerank accepts none, order, or aggregate; rewriteQuery controls retrieval-oriented query rewriting.

Response mapping

Each primary result contains either memory, chunk, or both only if the contract allows it. Branch on field presence rather than assuming one result shape.

Verification

  • Compare IDs using explicit v4-equivalent defaults, then test v5 hybrid behavior separately.
  • Cover all three modes, thresholds at 0 and 1, each rerank option, and query rewriting.
  • Cover every include alone and in combination, including empty results.
  • Verify filters, namespace isolation, result limits, and invalid body/query placement.

Profiles and buckets

v5 returns a maintained profile directly and gives profile bucket definitions their own namespace-scoped resource.

Remove search behavior from profile calls

Remove legacy q, threshold, and include. If the caller needs query-ranked results, issue a separate v5 search request. Move containerTag to the path and rename filters to singular filter.

Read the v5 profile shape

static and dynamic are always returned and cannot be disabled. Omit buckets in the request to return every effective custom bucket; pass up to 50 names to narrow only the bucket section.

Read bucket definitions

The response changes from key/description objects to a map:

Add or edit namespace buckets

Send one to 50 name-to-description entries. Existing namespace names are updated, new names are added, and omitted namespace buckets remain unchanged.

Delete namespace buckets

Names must be unique. Organization-owned buckets can appear in the effective GET response but cannot be changed or removed through namespace PUT or DELETE calls.

With the SDK

supermemory.profile takes no query. body is optional and accepts only filter and buckets. Read profile.static, profile.dynamic, and profile.buckets[name] as arrays of { id, memory }.

Verification

  • Confirm every profile response contains static, dynamic, and buckets.
  • Compare omitted buckets with one-name and multi-name narrowing.
  • Add, edit, and delete a namespace bucket without replacing omitted buckets.
  • Attempt to mutate an inherited organization bucket and expect the documented error.

Memory forgetting

v5 scopes forgetting to one namespace and returns the same result envelope for exact and semantic requests.

Choose exact or semantic forgetting

Forget exact IDs

Send 1–500 IDs. The response reports successful IDs in matches and missing or ineligible IDs in errors, so HTTP success does not imply every requested ID changed.

Preview a semantic request

dryRun: true performs selection without changing memory state. dryRun: false forgets the memories selected when that request executes.

Avoid selection drift

Use this workflow when a human or policy must approve the exact set. Re-running the semantic request with dryRun: false can select a different set if memories changed after preview.

Read the normalized response

count always equals matches.length. Both dry-run and applied semantic requests use this shape; the payload alone does not replace your record of which mode was sent.

With the SDK

dryRun is required on forgetMatching. Both calls return { count, matches, errors }.

Removed memory-write routes

Direct v4 memory creation and version updates (client.memories.add, client.memories.updateMemory) have no v5 replacement. Ingest source material through document routes and update the canonical document when facts change.

Verification

  • Exercise all-success, partial-success, duplicate, unknown, and cross-namespace ID sets.
  • Confirm dry runs leave matched memories recallable.
  • Apply reviewed IDs exactly and confirm normal recall excludes them.
  • Persist the request mode alongside audit logs for semantic operations.

Namespaces

v5 renames the public isolation boundary from container tag to namespace. Existing values remain valid identifiers; no stored data rename is required.

Endpoint mapping

GET /ns is an alias for GET /namespaces. Prefer /namespaces in new integrations.

List namespaces

The list is paginated: GET /namespaces?page=1&limit=10 returns {namespaces, pagination}, newest first, with limit up to 100. Each entry now exposes id, namespace, documentCount, memoryCount, nullable description, and system.createdAt/updatedAt. Update readers that still expect containerTag, flat timestamps, or unbounded internal settings.

Read and update settings

The public GET and PATCH shapes contain only namespace, supportingContext, and lifecycle timestamps. Profile buckets have their own /profile/buckets resource and are not namespace settings. Send supportingContext: null to remove existing context. Omitting the field entirely is invalid because PATCH requires at least one supported setting.

Permanently delete a namespace

With no moveTo, deletion is synchronous and returns 200 with status: "deleted", deletedDocumentsCount, and deletedMemoriesCount. Branch on status (deleted or queued) to tell the two outcomes apart. This removes the namespace and its content.

Move then remove a namespace

moveTo is a query parameter. This returns 202 with status: "queued" and operationId. The destination must differ from the source. Do not treat acceptance as completed migration. Legacy merge can accept multiple sources; v5 moves one source per request. Run multi-source migrations sequentially and record each operation independently.

With the SDK

Replace calls to /v3/container-tags/* with supermemory.namespaces:
namespaces.list() returns { namespaces, pagination }, where each namespace is { id, namespace, documentCount, memoryCount, description, system }. A delete without moveTo returns { status: "deleted", namespace, deletedDocumentsCount, deletedMemoriesCount }; with moveTo it returns { status: "queued", operationId, namespace, moveTo }.

Verification

  • Confirm existing container-tag values resolve unchanged as namespace paths.
  • Compare namespace counts with namespace-scoped document and memory lists.
  • Verify a permanent delete returns final counts while a move returns 202.
  • Verify restricted callers cannot read or mutate namespaces outside their scope.
  • Verify only organization-authorized callers can change settings or lifecycle.

Organization settings

v5 exposes only the organization-wide context needed to guide memory formation. Internal controls and profile bucket mutation are no longer part of this settings resource.

Endpoint mapping

Read organization settings

Remove readers for legacy settings that are not present in this allowlisted response. namespaceCount is informational and cannot be changed through PATCH.

Update organization context

The field is exhaustive: the supplied value replaces the existing context. Send null to remove it. Empty strings are rejected. Organization updates require an organization administrator. Do not silently fall back to namespace context when the caller receives 403.

With the SDK

Removed public operations

  • Organization profile-bucket mutation is not exposed through organization settings.
  • Bucket suggestion is not part of v5.
  • Organization data reset is not part of v5.
  • Namespace-owned profile buckets are managed through /ns/{namespace}/profile/buckets.

Verification

  • 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.
  • Verify non-admin callers receive 403 on PATCH.
  • Confirm removed fields are not required by downstream configuration code.

Typed filters

v5 uses one optional singular filter field for search, profiles, and list operations.

Shape

Fields may contain letters, numbers, _, ., and -. Expressions allow up to five nested levels and 200 operands per logical group.

Operator mapping

Before and after

With the SDK

filter is a typed object under body, not a JSON string. The same shape works in supermemory.list and supermemory.profile. Keys are literal: customer.plan is one field name, not a nested path.

Deterministic conversion

  1. Rename outer filters to filter.
  2. Recursively replace AND/OR objects with { operator, operands }.
  3. Rename key to field.
  4. Convert legacy flags into one explicit operator.
  5. Keep numeric values as JSON numbers rather than numeric strings.
  6. Remove legacy filterType, negate, numericOperator, and ignoreCase keys.

Verification

  • Compare result IDs for equality, inequality, contains, numeric, array, nested AND, and nested OR fixtures.
  • Add negative tests: legacy shapes, empty operands, incompatible value types, and unknown keys must return 400.
  • Confirm omitted filter preserves unfiltered behavior.

Verification and rollout

Treat migration as a behavioral comparison, not a raw response snapshot update.

Build deterministic fixtures

Use an isolated namespace with stable IDs and fixed source content. Include plaintext, URL, file, batch, metadata, grouping, profile facts, related memories, forgotten memories, and empty-result cases. Record each legacy request, v5 request, expected semantic result, and intentional difference. Never compare generated IDs, signed URLs, timing, or JSON object order unless the contract guarantees them.

Compare writes

  • Repeated POST appends or diffs; PATCH replaces canonical content.
  • Batch outcomes list accepted documents first, then failures, and surface partial failures; match by ID, not position.
  • Metadata-only updates leave source content unchanged.
  • Accepted writes are polled until processing reaches a terminal state.

Compare reads and recall

  • Document includes are absent when omitted and empty arrays when requested without results.
  • Unified list responses populate only the selected resource array.
  • metadata is always an object, {} when empty; it is never null.
  • Search parity uses explicit v4-equivalent mode and threshold before testing v5 defaults.
  • Profiles always contain static, dynamic, and bucket sections.

Exercise boundaries

Classify differences

Do not normalize away an undocumented difference. Capture the request pair, namespace, IDs, response status, and minimal response fragments needed to reproduce it.

Cut over by domain

  1. Ship v5 request construction behind a per-domain flag.
  2. Dual-read or shadow-call where side effects allow it.
  3. Switch ingestion, content management, search, profiles, then settings independently.
  4. Monitor validation failures, authorization failures, latency, empty-result rate, and processing failures.
  5. Retain the legacy path until the observation window passes.

Completion checklist

  • No application API call accidentally uses a /v5 prefix.
  • Connector calls use /ns/{namespace}/connectors or supermemory.connectors.*, not /v3/connections.
  • No legacy field aliases or response readers remain.
  • Every changed default is either accepted intentionally or passed explicitly.
  • Rollback restores the previous caller without requiring data repair.

Operations without a direct replacement

  • Direct memory creation and version updates: ingest or replace a source document instead.
  • Organization bucket suggestion and organization reset: not part of the v5 public surface.
  • Connector resource listing and hosted pickers from /v3/connections: use supermemory.connectors.get with include: ["syncs", "picker"] instead. Connector create, list, get, update, delete, and sync all have v5 routes under /ns/{namespace}/connectors.
Use the v5 reference for the stable v5 API. /reference always points to the latest public version.