Writing memories

Store one memory

POST/api/v1/memory/store

In the SDKs: add

Authentication

Every call carries your API key in an X-API-Key header. Keys are created in the console.

X-WOS-Modeloptional

Picks the memory model that answers. Omit it and the account default is used.

Idempotency-Keyoptional

Makes a retry safe: the same key returns the first result instead of writing twice.

Request body

JSON, required. Out-of-range values are refused with a 400 rather than quietly clamped.

user_id string required

The store to operate on. Stores are explicit: create one first or use the built-in "default".

content string required
metadata object

Optional. Known keys: event_date (RFC3339 — when it actually happened), speaker ("me" for the agent’s own words, or a REGISTERED person’s name). Unknown keys are dropped.

image object

An image to store with the text (Tablet 2 and newer; an older model refuses the write rather than keeping the caption and dropping the image). content may be EMPTY when you pass one — then the image IS the memory and is searchable on its own.

Billed in tokens, the same unit as text: pixel area / 556.7, counted with the long edge capped at 1568px — so a 2500px image and a 1568px one cost the same. That works out to about 1.35x what the same area of text would cost, and to a ceiling of 4,417 tokens for any single image. The ceiling is reserved against your balance before the call; the measured value is charged after and is never higher.

What we keep is NOT your original. Above 1568px on the long edge the image is downscaled to 1568 on the way in, and that smaller picture is what gets embedded, stored and handed back. Downscaling re-encodes: lossless formats are written as WebP, so a 2500px PNG comes back at 1568px as image/webp; JPEG stays JPEG, and below 1568px the bytes are untouched. Keep your own copy, or put its URL in reference, if you need the full-resolution file.

Size window: both edges >= 700px, long edge <= 2500px; outside it the call is a 400. Below 700px a flat minimum applies, so a smaller image would cost the same as a 700px one; above 2500px we will not decode the file at all. Base64 runs ~33% larger than the file and the body cap is 10MB.

Returns

The 200 body. Fields nested one level are shown as parent.child.

id string

Empty when status is "duplicate".

status string

"stored" on success — match on the prefix, since the string may carry a suffix, usually 1 — or "duplicate" when the write was dropped because a memory close enough IN MEANING already exists. Match on the prefix, not on equality.

note string

Present when something non-fatal was dropped (e.g. a speaker tag on a duplicate).

Example

cURL
curl -X POST https://api.wontopos.com/api/v1/memory/store \
  -H "X-API-Key: $WOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"alice","content":"she prefers tea over coffee"}'

Status codes

StatusMeaning
200Success.
400Invalid body — or an UNREGISTERED speaker name (register it first: POST /api/v1/memory/speakers; the error carries a "speaker" field). Nothing is stored.
401Missing or invalid API key.
404Store (user_id) does not exist. Create it first: POST /api/v1/memory/collection.
429Rate limited (per-account, per-tier RPM). Retry after the indicated delay.

Rate limits per tier and the full status list are in Errors & limits.

In the SDKs

The Python, TypeScript, and Rust SDKs wrap this endpoint so you do not build the request by hand — pip install wontopos, npm i wontopos, or cargo add wontopos, then the method list is on the SDK reference. A coding agent can take the whole API in one file at llms.txt, or over MCP with npx -y wontopos-mcp.