Getting Started
Migrating from Mem0
Move your memories and your calling code from Mem0 to MemorySync. The import runs through one endpoint, and you can keep both providers live until your own queries look right.
Key differences
| Mem0 | MemorySync | What it means for your code |
|---|---|---|
user_id passed per call | X-End-User-ID request header | Isolation is enforced by the API, so a read cannot be widened by a forgotten filter argument. |
filters={"user_id": ...} on search | Scope header, not a filter | filters is left free for your own tags and metadata. |
messages=[...] extracted into facts | text — one statement per record | You decide what is worth storing, so what comes back is what you put in. |
top_k | k | Same meaning, shorter name. |
| Org and project ids on the client | X-Project-ID request header | One key can serve several projects without new client instances. |
| No update on the managed API | PATCH /memory/{memory_id} | Tags, importance, metadata, and source can be corrected in place. |
Install the client
python -m pip install memorysync==1.1.1
import osfrom memorysync import MemorySyncClientclient = MemorySyncClient(api_key=os.environ["MEMORYSYNC_API_KEY"],base_url="https://api.memorysync.io",project_id=os.environ["MEMORYSYNC_PROJECT_ID"],end_user_id="user-123",)
Operation by operation
client.add(messages="User prefers dark mode",user_id="alice",)
results = client.search(query="user preferences",filters={"user_id": "alice"},top_k=5,)
memories = client.get_all(filters={"user_id": "alice"})client.delete(memory_id="mem_123")
Where Mem0 returns an extracted fact it decided to keep, MemorySync returns the record you wrote. If you were reconciling extraction output against your own database, that reconciliation step disappears.
Move your existing memories
- 1Export from Mem0. The dashboard export is the least code; the export API works too, and returns records with
id,content,metadata, andcreated_at. - 2Group the exported records by their Mem0
user_id. Each group becomes one MemorySync end-user scope. - 3Import each group with bulk add, keeping the original id in
metadataso the two systems stay reconcilable. - 4Read the per-item results. A
207with skipped items is a normal outcome, not a failure.
import json, osfrom memorysync import MemorySyncClientwith open("mem0_export.json") as handle:export = json.load(handle)# one MemorySync client per end user keeps the scope explicitby_user: dict[str, list[dict]] = {}for record in export["memories"]:if record.get("content"):by_user.setdefault(record.get("user_id", "unknown"), []).append(record)for user_id, records in by_user.items():client = MemorySyncClient(api_key=os.environ["MEMORYSYNC_API_KEY"],base_url="https://api.memorysync.io",project_id=os.environ["MEMORYSYNC_PROJECT_ID"],end_user_id=user_id,)result = client.bulk_add([{"text": record["content"],"source": "import","metadata": {"mem0_id": record.get("id"), **(record.get("metadata") or {})},}for record in records],deduplicate=True,)print(user_id, result.created, "created,", result.skipped, "skipped")
Worth knowing before you cut over
- Writes are durable when
addreturns. There is no event id to poll and no queued state to wait through before a memory is retrievable. - Nothing is silently rewritten. A record changes only when you call update or forget, so your memory count reflects your own decisions.
- A memory belongs to one end user. Cross-user reads are not a filter you have to remember to apply.
- Retrieval returns whole records with their metadata, not fragments to reassemble.
- Keep your Mem0 export until you have run a full usage cycle here. It is the cheapest rollback available.