The official Python library for the Supermemory v5 API, with sync and async clients built on httpx.
Upgrading from 3.x? v5 moves to the namespace-first v5 API. See MIGRATION.md.
pip install --pre supermemory # 5.0 release candidatesfrom supermemory import Supermemory
client = Supermemory() # reads SUPERMEMORY_API_KEY; or Supermemory(api_key="...")
client.add("user_alex", content="Alex prefers morning meetings.", id="pref-1")
response = client.search("user_alex", query="when does alex like to meet?", limit=5)
for result in response.results:
print(result)Every content operation is scoped to a namespace (a user ID, project ID, or anything you want to isolate memories by), passed as the first argument.
import asyncio
from supermemory import AsyncSupermemory
async_client = AsyncSupermemory()
async def main() -> None:
profile, results = await asyncio.gather(
async_client.profile("user_alex"),
async_client.search("user_alex", query="upcoming meetings"),
)
asyncio.run(main())Install supermemory[aiohttp] to use aiohttp as the async transport.
| Call | Endpoint |
|---|---|
client.add(namespace, content=...) |
POST /ns/{namespace}/document |
client.search(namespace, query=...) |
POST /ns/{namespace}/search |
client.profile(namespace) |
POST /ns/{namespace}/profile |
client.list(namespace, "documents" | "chunks" | "memories") |
POST /ns/{namespace}/list/{type} |
client.documents.{get, update, delete, batch_add, upload_file, replace_with_file, update_file} |
/ns/{namespace}/document… |
client.memories.{forget, forget_matching} |
/ns/{namespace}/memories… |
client.profiles.{get_buckets, set_buckets, delete_buckets} |
/ns/{namespace}/profile/buckets |
client.connectors.{list_all, list, create, get, update, delete, sync} |
/connectors, /ns/{namespace}/connectors… |
client.namespaces.{list, get, update, delete} |
/ns, /ns/{namespace} |
client.organization.{get, update} |
/organization |
Full parameter reference: reference.md.
Filters are plain dicts (typed as FilterExpressionParams), combinable with and / or:
response = client.search(
"user_alex",
query="launch plans",
filter={
"operator": "and",
"operands": [
{"field": "source", "operator": "eq", "value": "slack"},
{"field": "priority", "operator": "gte", "value": 3},
],
},
)The same filter shape works for client.list(...) and client.profile(...).
page = client.list("user_alex", "documents", page=1, limit=50, sort="createdAt", order="desc")
for document in page.documents or []:
print(document.id, document.title)
print(page.pagination)with open("notes.pdf", "rb") as f:
client.documents.upload_file("user_alex", file=f)Same exception classes as 3.x. Non-2xx responses raise a subclass of supermemory.APIStatusError with status_code, body, message, request, and response. Network failures raise APIConnectionError (APITimeoutError for timeouts):
import supermemory
from supermemory import Supermemory
client = Supermemory()
try:
client.documents.get("user_alex", "missing-id")
except supermemory.NotFoundError:
...
except supermemory.RateLimitError as e:
print(e.response.headers.get("retry-after"))
except supermemory.APIStatusError as e:
print(e.status_code, e.body)
except supermemory.APIConnectionError:
...| Status | Error |
|---|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 409 | ConflictError |
| 422 | UnprocessableEntityError |
| 429 | RateLimitError |
| >=500 | InternalServerError |
Connection errors, 408, 429, and 5xx responses are retried twice with exponential backoff, and requests time out after 60 seconds (5 seconds to connect). All of these can be set on the client, or for one request with with_options:
import httpx
client = Supermemory(max_retries=5, timeout=20.0, default_headers={"X-App": "my-app"})
client.with_options(max_retries=0, timeout=httpx.Timeout(5.0)).search("user_alex", query="...")Every method also takes extra_headers, extra_query, extra_body, and timeout:
client.search("user_alex", query="...", extra_headers={"X-Trace": "1"}, timeout=5)The client reads SUPERMEMORY_API_KEY, SUPERMEMORY_BASE_URL, and SUPERMEMORY_CUSTOM_HEADERS from the environment.
response = client.with_raw_response.search("user_alex", query="...")
print(response.headers.get("x-request-id"))
results = response.parse() # SearchResponseResponse models have .to_dict() and .to_json().
The SDK is generated from the live v5 OpenAPI spec with Fern's open-source Python generator, run locally in Docker. No hosted codegen service is involved. Don't edit src/supermemory by hand; CI fails if it doesn't match a fresh generation.
| To change | Edit |
|---|---|
| Method names, grouping, parameter names, hidden endpoints | fern/overlay.yaml (x-fern-sdk-group-name, x-fern-sdk-method-name, x-fern-parameter-name, x-fern-ignore) |
Type names (Document, Memory, Connector, …) |
fern/schemas.yaml |
| Generator options | fern/generators.yml |
| Client conventions (options, errors, per-call options) | custom/supermemory/_compat.py |
| Small fixes to Fern's generated core | custom/patches/*.patch |
scripts/generate fetches the spec, names its schemas, runs Fern, then layers custom/ on top.
scripts/generate # fetch /v5/openapi and regenerate (needs Docker, bun, uv)
SKIP_FETCH=1 scripts/generate # regenerate from the committed fern/openapi.json
uv run --group dev pytest # offline tests, including every snippet in README.md and MIGRATION.md
SUPERMEMORY_LIVE_API_KEY=... uv run --group dev pytest tests/live # against the real APIRunnable examples are in examples/.
- When the API deploy sends
openapi-updated(or on the daily backstop run), Generate SDK regenerates. If the SDK changed, it bumps the version and opens a PR with the tests already run. - Merging a PR that changes the version in
pyproject.tomlpublishes it to PyPI and creates a GitHub release. - To cut a specific version, run Generate SDK manually with
versionset.