Store one memory
POST/api/v1/memory/store
In the SDKs: add · add_with · add_idempotent · add_with_idempotent
Authentication
Every call carries your API key in an X-API-Key header. Keys are created in the console.
X-WOS-ModeloptionalPicks the memory model that answers. Omit it and Tablet 2 answers.
Idempotency-KeyoptionalMakes 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_idstring requiredThe store to operate on. Stores are explicit: create one first or use the built-in "default". Use the id the store was created with: 1-64 ASCII letters, digits, ., _ or -, starting with a letter or digit. Ids that differ only by case name one store.
contentstring requiredmetadataobjectOptional. 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.
imageobjectAn 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).
contentmay 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. A long edge from 1568px up to 2500px 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 usually comes back at 1568px as image/webp (a re-encode that would be bigger is dropped and your bytes kept); 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, image file <= 7MB; outside it the call is a 400 that says why. 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.
idstringEmpty when status is "duplicate".
statusstring"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.
notestringPresent when something non-fatal was dropped (e.g. a speaker tag on a duplicate).
Example
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
| Status | Meaning |
|---|---|
| 200 | Success. |
| 400 | Invalid body — or an UNREGISTERED speaker name (register it first: POST /api/v1/memory/speakers; the error carries a "speaker" field). Nothing is stored. |
| 401 | Missing or invalid API key. |
| 404 | Store (user_id) does not exist. Create it first: POST /api/v1/memory/collection. |
| 429 | Rate 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.