memory API

Memory as an API for AI agents. Three verbs — remember, recall, forget.


Getting started

Every memory account gets a private, sovereign store. You interact with it through a tiny HTTP API. No SDK required — just curl or fetch.

1. Register

curl -X POST https://memory.automators.work/v1/register \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com" }'

Response includes your api_key — shown only once. Save it now.

2. Authenticate

Every authenticated endpoint needs the Authorization header:

Authorization: Bearer ctxk_...

Memory API

POST/v1/remember

Stores a new memory. Content is embedded automatically.

Body

fieldtypenotes
contentstringrequired, max 20,000 chars
typestringoptional. Allowed: fact, preference, decision, task, correction, event, instruction, note. Default: note.
auto_classifybooleanoptional. If true and type is not provided, the LLM (Granite 4.0 H Micro) classifies the content into one of the allowed types. Adds ~300-600 ms.
tagsstring[]optional, used for filtering in recall
metadataobjectoptional, free-form JSON
supersedesstringoptional. ID of a prior entry this one supersedes. The prior entry is marked superseded_by and hidden from default recall/list. Use /chain to see the full history.

Idempotency: if an active entry already exists with the same (content, type), the server returns the existing entry with idempotent_hit: true and HTTP 200 instead of creating a duplicate (HTTP 201). Content hashes are 32-char SHA-256 prefixes stored as content_hash.

curl -X POST https://memory.automators.work/v1/remember \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "content": "User prefers concise answers in Spanish.",
    "type": "preference",
    "tags": ["user:alice", "lang:es"]
  }'

Response (201 Created)

{
  "id": "2026-04-17T14-22-03-8a4f2c",
  "content": "User prefers concise answers in Spanish.",
  "type": "preference",
  "tags": ["user:alice", "lang:es"],
  "metadata": {},
  "created_at": 1744900923000,
  "took_ms": 142
}

POST/v1/remember/from-session

Extracts atomic memories from a free-form transcript using an LLM. Ideal for post-session mining.

Body

fieldtypenotes
transcriptstring20–100,000 chars. Older content is trimmed to keep the recent tail.
max_memoriesnumberdefault 10, max 20
curl -X POST https://memory.automators.work/v1/remember/from-session \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "transcript": "User: I prefer answers in Spanish.\nAssistant: Got it.\nUser: Also I use Rust daily.",
    "max_memories": 5
  }'

Response (201 Created)

{
  "extracted": 2,
  "entries": [
    { "id": "...", "content": "User prefers answers in Spanish", "type": "preference", "tags": ["lang:es"] },
    { "id": "...", "content": "User uses Rust daily", "type": "fact", "tags": ["lang:rust"] }
  ],
  "took_ms": { "llm": 1240, "total": 1890 },
  "model": "@cf/ibm-granite/granite-4.0-h-micro"
}

Default model is IBM Granite 4.0 H Micro (131K context, efficient for structured JSON extraction). Each extracted memory is committed individually and auto-embedded.

POST/v1/recall

Hybrid search across two channels fused with Reciprocal Rank Fusion:

After fusion: correction boost (2× for type:"correction") then MMR diversity (λ=0.7 default). Disable RRF to save a few ms if you only want vector search.

Body

fieldtypenotes
querystringrequired
top_knumberdefault 10, max 50
coarse_top_nnumberdefault 100, max 500 — candidates after coarse pass
typestringfilter by type (e.g. fact, preference, correction)
tagsstring[]ALL tags must match
sincenumberunix ms — only entries created after
rrfbooleandefault true — fuse vector + full-text channels. Set false for vector-only (faster on large memories).
mmrbooleandefault true — applies MMR diversity so near-duplicates don't crowd results
lambdanumberdefault 0.7 — 1.0 = pure relevance, 0.0 = pure diversity
correction_boostnumberdefault 2.0 — score multiplier for entries with type:"correction"
synthesizebooleandefault false — opt-in LLM call (Granite 4.0 H Micro) that returns an answer field synthesized from the top results. Adds ~500-1500 ms.

Tip: use type:"correction" when remembering overrides of prior information. They'll surface above older entries at recall time.

curl -X POST https://memory.automators.work/v1/recall \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "query": "how does this user like their responses?",
    "top_k": 3,
    "tags": ["user:alice"]
  }'

Response

{
  "query": "how does this user like their responses?",
  "results": [
    {
      "id": "2026-04-17T14-22-03-8a4f2c",
      "content": "User prefers concise answers in Spanish.",
      "type": "preference",
      "tags": ["user:alice", "lang:es"],
      "metadata": {},
      "created_at": 1744900923000,
      "score": 0.0317,
      "raw_score": 0.0317,
      "boosted": false,
      "channel_scores": { "vector": 0.871, "text": 2.14 }
    }
  ],
  "coarse_scanned": 523,
  "fine_scanned": 100,
  "text_scanned": 42,
  "total_memories": 523,
  "applied": {
    "channels": ["vector", "text"],
    "rrf": true, "mmr": true, "lambda": 0.7, "correction_boost": 2
  },
  "took_ms": {
    "embed": 34, "coarse": 2, "load_full": 6, "fine": 6,
    "text": 8, "fusion": 1, "mmr": 3, "total": 60
  }
}

Note: when RRF is on, score is the fused RRF score (small numeric range, ~0.01–0.1). With RRF off, score is the cosine similarity (0–1). Use channel_scores to see each channel's raw contribution.

GET/v1/memories

List memories chronologically (newest first), cursor-paginated.

Query params: type, since (unix ms), limit (default 50, max 200), cursor.

curl -H "Authorization: Bearer ctxk_..." \
  "https://memory.automators.work/v1/memories?type=preference&limit=20"

GET/v1/memories/:id

Fetch a specific memory by id.

curl -H "Authorization: Bearer ctxk_..." \
  https://memory.automators.work/v1/memories/2026-04-17T14-22-03-8a4f2c

GET/v1/memories/:id/chain

Walk the supersession chain that contains this entry. Returns entries ordered from oldest to newest, following supersedes backwards and superseded_by forwards.

curl -H "Authorization: Bearer ctxk_..." \
  https://memory.automators.work/v1/memories/2026-04-17T14-22-03-8a4f2c/chain
{
  "anchor": "2026-04-17T14-22-03-8a4f2c",
  "length": 3,
  "chain": [
    { "id": "2026-04-15T...-a1", "content": "User prefers Rust",
      "superseded_by": "2026-04-16T...-b2", ... },
    { "id": "2026-04-16T...-b2", "content": "User now prefers Go",
      "supersedes": "2026-04-15T...-a1",
      "superseded_by": "2026-04-17T14-22-03-8a4f2c", ... },
    { "id": "2026-04-17T14-22-03-8a4f2c", "content": "User switched back to Rust",
      "supersedes": "2026-04-16T...-b2", ... }
  ]
}

DELETE/v1/memories/:id

Soft-delete (tombstone). The memory stops appearing in recalls and lists, but the event stays in history.

curl -X DELETE -H "Authorization: Bearer ctxk_..." \
  https://memory.automators.work/v1/memories/2026-04-17T14-22-03-8a4f2c

POST/v1/forget

Forget multiple memories, either by explicit ids or by semantic query.

Mode 1 — explicit ids:

curl -X POST https://memory.automators.work/v1/forget \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["2026-04-17T14-22-03-8a4f2c", "2026-04-16T09-11-22-aabbcc"] }'

Mode 2 — semantic, with safety dry-run:

# First call: no confirm → returns matches without deleting
curl -X POST https://memory.automators.work/v1/forget \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{ "query": "anything about old API keys" }'

# Second call: confirm:true → actually tombstones them
curl -X POST https://memory.automators.work/v1/forget \
  -H "Authorization: Bearer ctxk_..." \
  -H "Content-Type: application/json" \
  -d '{ "query": "anything about old API keys", "confirm": true }'

Account & data

GET/v1/me

{
  "user_id": "u_...",
  "email": "you@example.com",
  "plan": "free",
  "status": "active",
  "created_at": 1744900923000,
  "created_at_iso": "2026-04-17T14:22:03.000Z"
}

GET/v1/stats

Counters for your memory store.

{
  "total": 523,
  "deleted": 12,
  "by_type": { "note": 400, "preference": 80, "fact": 43 },
  "oldest": 1700000000000,
  "newest": 1744900923000,
  "storage_bytes_estimate": 1847324
}

GET/v1/export

Downloads all your active (non-deleted) memories as newline-delimited JSON. No vendor lock-in — you can always take your data with you.

curl -H "Authorization: Bearer ctxk_..." \
  https://memory.automators.work/v1/export > memories.jsonl

Limits & errors

Rate limits

planrequests / hour
free100
pro10,000
enterprise100,000

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.

Error format

{ "error": "human-readable message" }
statusmeaning
400Bad request (missing / invalid body)
401Missing or invalid API key
404Memory not found
409Email already registered
429Rate limit exceeded
500Internal error

Questions? Back home · API info JSON