---
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+.