Bulk Import
Move a large export in one upload. Returns a job id immediately, then reports progress until it finishes.
When to use this instead of bulk add
POST /memory/bulk-add accepts up to 50 records per request, because every record runs the extraction pipeline and a larger request would exceed the request timeout. For anything bigger — a migration out of another system, a backfill of historical data — upload the file once here and poll the job. The records are ingested through the same pipeline either way, so nothing is stored differently for having arrived asynchronously.
| Rule | Contract |
|---|---|
| Payload | A JSONL file, or a .json file containing an array. One record per line or per array entry. |
| Record shape | The same fields bulk-add accepts: text (required), source, tags, importance, metadata, client_ref. |
| Ceiling | Up to 100,000 records in one job. Split larger files. |
| Validation | The whole payload is checked before the job is accepted. A file with unusable rows is refused with their line numbers, unless continue_on_error is set. |
| Safe retries | Send client_ref on every record and set resume=true. Records a previous run already stored are reported as already_imported rather than stored again, so an interrupted import can simply be run again. |
| Billing | One unit per memory created, charged as the worker progresses. Identical to every other ingestion path. |
| Isolation | Import work runs on a separate queue from real-time ingestion, so a large migration does not slow down live writes. |
Upload a payload
| Field | Type | Contract |
|---|---|---|
file | file | Required. The JSONL or JSON payload, sent as multipart form data. |
end_user_id | string | The end user every record belongs to. Required with an API key; mirrors X-End-User-ID. Resolved once for the whole job. |
resume | boolean | Requires client_ref on every record. Makes re-running the same file safe. |
continue_on_error | boolean | Accept the file and skip unusable rows instead of refusing it. |
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="usr_7f3a9c2e",)with open("memories.jsonl", "rb") as handle:job = client.create_import(handle,filename="memories.jsonl",end_user_id="alice",resume=True,)print(job["id"], job["status"])
Poll the job
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="usr_7f3a9c2e",)job = client.get_import(job_id)print(job["status"], job["processed_rows"], "/", job["total_rows"])
| Field | Meaning |
|---|---|
status | One of queued, validating, processing, completed, failed, cancelled. |
total_rows · processed_rows | Records counted during validation, and how many the worker has decided about. |
progress_percentage | Stays below 100 until the job is genuinely finished, so reaching 100 means done. |
created | Records that produced at least one memory. |
memories_created | Memories stored. Not the same as created — one record routinely produces several. This is the figure billed. |
already_imported | Records a previous run had already stored under the same client_ref. |
skipped | Records deduplicated or filtered as low value. |
failed · invalid_rows | Records the pipeline refused, with line numbers. |
Read the counters. Skipped and failed records are normal outcomes, not errors.
Records already imported are stored. Re-run the file with resume to finish it without duplicates.
Records already imported are stored. The counters say how far it got.
List recent jobs
Newest first, scoped to your tenant. Accepts status, limit and offset.
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="usr_7f3a9c2e",)for job in client.list_imports(limit=5)["jobs"]:print(job["id"], job["status"], job["created"])
Cancel a running job
Asks the worker to stop between batches. Records already imported stay imported, and the counters report how far it reached. Cancelling a finished job is a no-op rather than an error, so a repeated click is harmless.
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="usr_7f3a9c2e",)job = client.cancel_import(job_id)print(job["status"], job["created"], "already imported")
From the CLI
The CLI wraps all of this. memorysync import <file> --resume --async --wait uploads the file and polls until it finishes; memorysync import-status lists recent jobs or reports one, and --cancel stops it.
memorysync import memories.jsonl --user alice --resume --async --waitmemorysync import-statusmemorysync import-status <job-id> --cancel