--- title: 'Supermemory SDK' sidebarTitle: "Supermemory SDK" description: 'Official Python and JavaScript SDKs for Supermemory' icon: "/images/supermemory.svg" --- pip install supermemory npm install supermemory Both SDKs also work against [self-hosted Supermemory](/self-hosting/overview) running `supermemory-server` v0.0.9 or later. Pass `baseUrl: "http://localhost:6767"` (TypeScript) or `base_url="http://localhost:6767"` (Python) when creating the client. ## Install the TypeScript SDK ```bash npm i supermemory ``` ## Start a TypeScript client ```typescript import { Supermemory } from "supermemory"; const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); ``` One rule for every call: URL values first as positional arguments (`namespace`, then `id` where there is one), then a single object with everything else. A namespace scopes memories to one user, workspace, or tenant, and you pass it on every call. ## Add ```typescript const { id, status } = await supermemory.add("user_123", { content: "Meeting notes from Q1 planning", id: "meeting-q1", // optional, your own id; the response echoes it metadata: { category: "engineering", priority: "high" }, dreaming: "instant", }); ``` `dreaming` defaults to `"dynamic"`, which batches memory extraction. A fresh namespace can show zero memories and an empty profile for minutes. Pass `dreaming: "instant"` in quick-start flows and anywhere the next step is a memory search or a profile read. ## Search ```typescript const { results, searchTime } = await supermemory.search("user_123", { query: "planning notes", limit: 10, }); for (const result of results) { console.log(result.memory ?? result.chunk, result.similarity); } ``` `searchMode` is `"hybrid"` (default), `"memories"`, or `"chunks"`. Filter on metadata with a typed expression: ```typescript const { results } = await supermemory.search("user_123", { query: "design document", filter: { field: "category", operator: "eq", value: "engineering" }, searchMode: "chunks", }); ``` Two defaults changed from the legacy SDK: `threshold` is now `0.3` (was `0.6`) and `searchMode` is now `hybrid` (was `memories`). Set both explicitly if you compare results against old code. ## Profile ```typescript const { profile } = await supermemory.profile("user_123"); console.log(profile.static); console.log(profile.dynamic); console.log(profile.buckets); ``` Buckets group profile facts under names you define: ```typescript await supermemory.profiles.setBuckets("user_123", { buckets: { work: "Job, team, and current projects" }, }); const buckets = await supermemory.profiles.getBuckets("user_123"); await supermemory.profiles.deleteBuckets("user_123", { buckets: ["work"], }); ``` ## List ```typescript const { documents, pagination } = await supermemory.list("user_123", "documents", { page: 1, limit: 20, sort: "createdAt", order: "desc", }); console.log(documents[0]?.system.status, pagination.totalPages); ``` `type` is required: `"documents"`, `"chunks"`, or `"memories"`. The response always has `documents`, `chunks`, `memories`, and `pagination`, and only the requested array is filled. Pass `{ filter }` to narrow the list. ## Documents ```typescript const doc = await supermemory.documents.get("user_123", "meeting-q1", { include: ["chunks", "memories"], }); console.log(doc.title, doc.summary, doc.system.status); await supermemory.documents.update("user_123", "meeting-q1", { metadata: { priority: "low" }, }); await supermemory.documents.batchAdd("user_123", { documents: [{ content: "First note" }, { content: "Second note" }], }); await supermemory.documents.uploadFile("user_123", { // file is a File or Blob file, metadata: JSON.stringify({ source: "upload" }), }); const { count, errors } = await supermemory.documents.delete("user_123", { ids: ["meeting-q1"], }); ``` `uploadFile` is multipart, so `metadata` is a JSON string there. `delete` can return partial failures, so check `errors` as well as `count`. ## Memories ```typescript const preview = await supermemory.memories.forgetMatching("user_123", { query: "old office address", dryRun: true, }); const { count } = await supermemory.memories.forget("user_123", { ids: preview.matches.map((match) => match.id), }); ``` `dryRun` is required on `forgetMatching`. Preview with `dryRun: true`, review `matches`, then forget by id. There is no direct memory create or update: ingest or update the source document instead. ## Namespaces ```typescript const { namespaces, pagination } = await supermemory.namespaces.list({ limit: 50 }); const ns = await supermemory.namespaces.get("user_123"); console.log(ns.supportingContext, namespaces[0]?.documentCount, pagination.totalPages); await supermemory.namespaces.update("user_123", { supportingContext: "A paying customer on the Pro plan", }); await supermemory.namespaces.delete("user_123", { // optional, moves content instead of deleting it moveTo: "archive", }); ``` ## Organization ```typescript const { organizationalContext, namespaceCount } = await supermemory.organization.get(); await supermemory.organization.update({ organizationalContext: "Acme sells billing software to dental clinics", }); ``` ## Connectors ```typescript const { id, authorization } = await supermemory.connectors.create("user_123", { provider: "notion", redirectUrl: "https://app.example.com/connected", }); // send the user to authorization.url before authorization.expiresAt const connectors = await supermemory.connectors.list("user_123"); const everyConnector = await supermemory.connectors.listAll(); const connector = await supermemory.connectors.get("user_123", id, { include: ["syncs", "picker"], }); console.log(connector.latestRun?.system.status, connector.documentCount); await supermemory.connectors.update("user_123", id, { documentLimit: 500, }); await supermemory.connectors.sync("user_123", id); await supermemory.connectors.delete("user_123", id, { deleteDocuments: true }); ``` OAuth providers (`notion`, `google-drive`, `onedrive`, `gmail`, `github`) return an `authorization` link. Config providers start syncing right away and return `authorization: null`: ```typescript await supermemory.connectors.create("user_123", { provider: "web-crawler", config: { startUrl: "https://docs.example.com", crawlDepth: 2 }, }); ``` `sync` returns `{ id, status: "queued" }` and responds with 409 if a sync is already running. ### Error handling Every HTTP error throws a `SupermemoryError` with `statusCode`, `body`, and `rawResponse`. Common statuses have their own subclasses, all exported from the package root: `BadRequestError` (400), `UnauthorizedError` (401), `PaymentRequiredError` (402), `ForbiddenError` (403), `NotFoundError` (404), `ConflictError` (409), `InternalServerError` (500), and `ServiceUnavailableError` (503). A timeout throws `SupermemoryTimeoutError`; a network failure is a `SupermemoryError` without a `statusCode`. ```typescript import { Supermemory, NotFoundError, SupermemoryError } from "supermemory"; try { await supermemory.documents.get("user_123", "missing"); } catch (error) { if (error instanceof NotFoundError) { console.log("gone"); } else if (error instanceof SupermemoryError) { console.error(error.statusCode, error.body); } else { throw error; } } ``` ### Timeouts and retries The client retries connection errors, 408, 429, and 5xx responses twice with backoff. Tune it on the client or per call; the per-call options object is always the optional last argument. ```typescript const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY, timeoutInSeconds: 30, // default 60 maxRetries: 0, // default 2 }); await supermemory.search("user_123", { query: "planning notes" }, { timeoutInSeconds: 5, maxRetries: 3, abortSignal: controller.signal, }); ``` ## Install the Python SDK ```bash pip install supermemory ``` ## Start a Python client ```python import os from supermemory import Supermemory client = Supermemory( api_key=os.environ.get("SUPERMEMORY_API_KEY"), # Default, can be omitted ) # Add a document result = client.add( "user_123", content="Meeting notes from Q1 planning", id="meeting-q1", # optional, your own id; the response echoes it metadata={"category": "engineering", "priority": "high"}, dreaming="instant", ) print(result.id, result.status) # Search (hybrid by default: memories plus document chunks) response = client.search("user_123", query="planning notes", limit=10) for hit in response.results: print(hit.memory or hit.chunk, hit.similarity) # Get user profile profile = client.profile("user_123").profile print(profile.static) print(profile.dynamic) print(profile.buckets) ``` ## Run common Python operations ```python import json # Search document chunks with a filter results = client.search( "user_123", query="design document", search_mode="chunks", filter={"field": "category", "operator": "eq", "value": "engineering"}, ) # Profile buckets client.profiles.set_buckets("user_123", buckets={"work": "Job, team, and current projects"}) buckets = client.profiles.get_buckets("user_123") client.profiles.delete_buckets("user_123", buckets=["work"]) # List documents page = client.list("user_123", "documents", page=1, limit=20, sort="createdAt", order="desc") print(page.pagination.total_pages) # Get, update, batch add, upload doc = client.documents.get("user_123", "meeting-q1", include=["chunks", "memories"]) client.documents.update("user_123", "meeting-q1", metadata={"priority": "low"}) client.documents.batch_add( "user_123", documents=[{"content": "First note"}, {"content": "Second note"}], ) with open("notes.pdf", "rb") as f: client.documents.upload_file("user_123", file=f, metadata=json.dumps({"source": "upload"})) # Delete documents result = client.documents.delete("user_123", ids=["meeting-q1"]) # Forget memories: preview, then apply preview = client.memories.forget_matching("user_123", query="old office address", dry_run=True) client.memories.forget("user_123", ids=[m.id for m in preview.matches]) # Namespaces and organization page = client.namespaces.list() # page.namespaces, page.pagination ns = client.namespaces.get("user_123") client.namespaces.update("user_123", supporting_context="A paying customer on the Pro plan") client.namespaces.delete("user_123", move_to="archive") # optional, moves content instead of deleting it client.organization.update(organizational_context="Acme sells billing software to dental clinics") # Connectors setup = client.connectors.create( "user_123", request={"provider": "notion", "redirectUrl": "https://app.example.com/connected"}, ) # send the user to setup.authorization.url before setup.authorization.expires_at connector = client.connectors.get("user_123", setup.id, include=["syncs", "picker"]) client.connectors.sync("user_123", setup.id) client.connectors.delete("user_123", setup.id, delete_documents=True) ``` ## Handle Python SDK errors Failed requests raise `supermemory.APIStatusError` (`.status_code`, `.body`) or a subclass such as `NotFoundError` or `RateLimitError`. Network failures raise `supermemory.APIConnectionError`. Set `max_retries=` and `timeout=` on the client, or per call. `AsyncSupermemory` has the same methods, awaited. Requires Python 3.10+.