MemorySync
API Reference

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.

RuleContract
PayloadA JSONL file, or a .json file containing an array. One record per line or per array entry.
Record shapeThe same fields bulk-add accepts: text (required), source, tags, importance, metadata, client_ref.
CeilingUp to 100,000 records in one job. Split larger files.
ValidationThe 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 retriesSend 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.
BillingOne unit per memory created, charged as the worker progresses. Identical to every other ingestion path.
IsolationImport work runs on a separate queue from real-time ingestion, so a large migration does not slow down live writes.

Upload a payload

POST/imports
202 Accepted
FieldTypeContract
filefileRequired. The JSONL or JSON payload, sent as multipart form data.
end_user_idstringThe end user every record belongs to. Required with an API key; mirrors X-End-User-ID. Resolved once for the whole job.
resumebooleanRequires client_ref on every record. Makes re-running the same file safe.
continue_on_errorbooleanAccept the file and skip unusable rows instead of refusing it.
import os
from memorysync import MemorySyncClient
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="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

GET/imports/{id}
200 OK
import os
from memorysync import MemorySyncClient
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="usr_7f3a9c2e",
)
job = client.get_import(job_id)
print(job["status"], job["processed_rows"], "/", job["total_rows"])
FieldMeaning
statusOne of queued, validating, processing, completed, failed, cancelled.
total_rows · processed_rowsRecords counted during validation, and how many the worker has decided about.
progress_percentageStays below 100 until the job is genuinely finished, so reaching 100 means done.
createdRecords that produced at least one memory.
memories_createdMemories stored. Not the same as created — one record routinely produces several. This is the figure billed.
already_importedRecords a previous run had already stored under the same client_ref.
skippedRecords deduplicated or filtered as low value.
failed · invalid_rowsRecords the pipeline refused, with line numbers.
Terminal states
completed
Finished

Read the counters. Skipped and failed records are normal outcomes, not errors.

failed
Stopped

Records already imported are stored. Re-run the file with resume to finish it without duplicates.

cancelled
Stopped on request

Records already imported are stored. The counters say how far it got.

List recent jobs

GET/imports
200 OK

Newest first, scoped to your tenant. Accepts status, limit and offset.

import os
from memorysync import MemorySyncClient
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="usr_7f3a9c2e",
)
for job in client.list_imports(limit=5)["jobs"]:
print(job["id"], job["status"], job["created"])

Cancel a running job

POST/imports/{id}/cancel
200 OK

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 os
from memorysync import MemorySyncClient
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="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.

terminal
memorysync import memories.jsonl --user alice --resume --async --wait
memorysync import-status
memorysync import-status <job-id> --cancel

Safety notes