Memories
Store, retrieve, update, and delete memories. Memories are the core building blocks of Hebbrix - they store knowledge that your AI can recall later.
01. Overview
A memory is a piece of information that you want your AI to remember. This could be:
- User preferences ("User prefers dark mode")
- Facts from conversations ("User's birthday is January 15th")
- Knowledge from documents ("The API rate limit is 100 requests per minute")
- Any structured or unstructured data you want to store
02. Which endpoint should I use? /raw vs /process
There are two ways to store a memory. For almost everything, /v1/memories/raw is the better default. It gives the best retrieval recall, the lowest latency, and costs nothing extra. Reach for /v1/memories/process only when you need the LLM to curate your knowledge base.
| /memories/raw | /memories/process | |
|---|---|---|
| What it does | Stores your text verbatim, then indexes it (with automatic context-window chunking) in the background. No LLM. | Runs an LLM to extract clean atomic facts, resolve references, and supersede outdated info. |
| Retrieval recall | Highest. Keeps every word, so nothing the query might match is lost. | Lower. Extraction drops non-factual text and paraphrases away exact wording. |
| Write latency | ~1s | Several seconds (LLM extraction); use async for sub-second response. |
| LLM cost | None | Per-memory LLM call |
| Supersession / dedup | No. Both an old and a corrected fact are kept | Yes. Corrections replace old facts; redundant facts are merged |
Use /raw (default) for
- Chat history & agent memory
- Documents, notes, transcripts
- Fact stores & knowledge bases
- Bulk import & high-throughput writes
- Anywhere recall and speed matter most
Use /process when you need
- "Latest value wins" (users correct/update facts over time)
- Conflict resolution between contradictory facts
- Deduplicated, normalized atomic facts
- A curated, always-current knowledge base
/raw. Only reach for /process when the freshness and correctness of stored knowledge matters more than raw recall. Both index asynchronously; a memory becomes searchable a few seconds after the write.03. Endpoints
04. Response shape (POST /v1/memories)
The POST /v1/memories response is HTTP 200 and was enriched with collection, processing, and per-event summary fields alongside the existing results array:
collection_id: the resolved collection the memories were stored in.processing_status"async": the memory row is persisted and indexed in the background. PollGET /v1/memories/{id}(or use Background Jobs) until it is searchable.created_count,updated_count,skipped_count: a summary derived from the per-row events (ADD / UPDATE / NOOP).
results[].id is the PARENT Memory.id, retrievable via GET /v1/memories/{id}. The proposition-style ids you may see in search results (like uuid::subj=...) are a search-layer artifact and are NOT returned by POST /v1/memories.POST /v1/memories → HTTP 200
{
"results": [
{ "id": "mem_abc123", "event": "ADD", "memory": "User prefers dark mode" }
],
"collection_id": "col_default",
"processing_status": "async",
"created_count": 1,
"updated_count": 0,
"skipped_count": 0
}05. Destructive operations: dry-run & confirmation
Bulk deletes that wipe everything support two opt-in safety controls so you can preview the blast radius before committing. Both are backward compatible.
DELETE /v1/memories/all?dry_run=truereturns{"deleted_count":0,"dry_run":true,"would_delete":N}and deletes NOTHING. Use it to preview how many memories would be removed.- An optional header
X-Hebbrix-Confirm-Destructive: all-memoriesguards the real delete. If the header is PRESENT it must equalall-memoriesor the request is rejected with HTTP 400. If OMITTED, behavior is unchanged. - The same pattern applies to
DELETE /v1/collections/all, whose confirm value isall-collections.
import requests
BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": "Bearer <your-api-key>"}
# 1) Dry-run first: preview the blast radius, deletes NOTHING
preview = requests.delete(
f"{BASE}/memories/all",
headers=H,
params={"dry_run": "true"},
).json()
# {"deleted_count": 0, "dry_run": True, "would_delete": 1287}
print(f"Would delete {preview['would_delete']} memories")
# 2) Confirmed delete: header must equal "all-memories" if present
result = requests.delete(
f"{BASE}/memories/all",
headers={**H, "X-Hebbrix-Confirm-Destructive": "all-memories"},
).json()
print(f"Deleted {result['deleted_count']} memories")
# Same safety pattern for collections (confirm value "all-collections")
requests.delete(
f"{BASE}/collections/all",
headers={**H, "X-Hebbrix-Confirm-Destructive": "all-collections"},
)06. Code Examples
Create a Memory
import asyncio
from hebbrix import MemoryClient
async def main():
async with MemoryClient(api_key="mem_sk_...") as client:
collection = await client.collections.create(name="my-agent")
# Simple memory (SDK calls the smart-extract POST /v1/memories endpoint)
memory = await client.memories.create(
collection_id=collection["id"],
content="User's favorite color is blue",
)
# Memory with importance + metadata (tags live inside metadata)
await client.memories.create(
collection_id=collection["id"],
content="User completed Python certification on 2024-01-15",
importance=0.8,
metadata={
"tags": ["education", "python"],
"certification_provider": "Coursera",
"completion_date": "2024-01-15",
},
)
asyncio.run(main())Process Conversations (fact extraction)
import os
import requests
BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"}
# POST /v1/memories/process: hand it a chat transcript; the backend
# extracts atomic facts, detects conflicts, and emits ADD/UPDATE/NOOP
# events for each resulting memory.
r = requests.post(
f"{BASE}/memories/process",
headers=H,
json={
"messages": [
{"role": "user", "content": "Hi! My name is Alex and I work at Acme Corp."},
{"role": "assistant", "content": "Nice to meet you, Alex!"},
]
},
)
result = r.json()
print(f"Facts extracted: {result['facts_extracted']}")
print(f"Created: {result['memories_created']}")
print(f"Updated: {result['memories_updated']}")
# Later, user corrects their name: the old memory is updated
r = requests.post(
f"{BASE}/memories/process",
headers=H,
json={
"messages": [
{"role": "user", "content": "Actually, my name is Jordan, not Alex."},
{"role": "assistant", "content": "No problem, Jordan!"},
]
},
)
result = r.json()
# result["events"][0]["event"] == "UPDATE"
# result["events"][0]["previous_content"] == "Alex is the user's name"Batch Create
import os
import requests
BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"}
# POST /v1/memories/batch: create multiple memories in one request (max 100).
# Note: collection_id is top-level, NOT per-memory.
memories = [
{"content": "User prefers email over phone calls"},
{"content": "User works in software development"},
{"content": "User is based in EST timezone"},
]
r = requests.post(
f"{BASE}/memories/batch",
headers=H,
json={
"memories": memories,
"collection_id": "col_default",
},
)
result = r.json()
print(f"Created {result['created']} memories")List and Filter (SDK)
import asyncio
import os
from hebbrix import MemoryClient
async def main():
async with MemoryClient(api_key=os.environ["HEBBRIX_API_KEY"]) as client:
# --- Explicit page-at-a-time access ---
page = await client.memories.list_page(limit=50)
# page = {"items": [...], "next_cursor": str | None,
# "has_more": bool, "total_count": int}
print(f"Showing {len(page['items'])} of {page['total_count']} memories")
# Fetch the next page if there is one
if page["has_more"]:
next_page = await client.memories.list_page(
cursor=page["next_cursor"], limit=50
)
print(f"Next page has {len(next_page['items'])} memories")
# Filter by collection
page = await client.memories.list_page(
collection_id="col_customer_support", limit=20
)
# --- Simple "give me everything" iteration ---
# iter_all follows next_cursor until has_more == False
async for memory in client.memories.iter_all(collection_id="col_customer_support"):
print(memory["id"], memory["content"][:80])
asyncio.run(main())List and Filter (raw HTTP)
import os
import requests
BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"}
# List all memories (cursor-paginated response)
r = requests.get(f"{BASE}/memories", headers=H, params={"limit": 50})
page = r.json() # {"items": [...], "next_cursor": ..., "has_more": ..., "total_count": ...}
# Paginate through all
cursor = None
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
page = requests.get(f"{BASE}/memories", headers=H, params=params).json()
for memory in page["items"]:
process(memory)
if not page.get("has_more") or not page.get("next_cursor"):
break
cursor = page["next_cursor"]07. cURL Examples
/v1/memoriescurl -X POST "https://api.hebbrix.com/v1/memories" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "User prefers dark mode",
"tags": [
"preferences"
]
}'/v1/memories?limit=10curl -X GET "https://api.hebbrix.com/v1/memories?limit=10" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"/v1/memories/mem_abc123curl -X DELETE "https://api.hebbrix.com/v1/memories/mem_abc123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"/v1/memories/processcurl -X POST "https://api.hebbrix.com/v1/memories/process" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "My name is Jordan and I work at Acme Corp."
},
{
"role": "assistant",
"content": "Nice to meet you, Jordan!"
}
]
}'/v1/memories/bulk-deletecurl -X POST "https://api.hebbrix.com/v1/memories/bulk-delete" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
"mem_abc123",
"mem_def456"
]
}'/v1/memories/allcurl -X DELETE "https://api.hebbrix.com/v1/memories/all" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"08. Memory Lifecycle
When you create a memory, Hebbrix automatically:
- Embeds the Content. Converts text to vector embeddings for semantic search.
- Calculates Importance. Analyzes content to determine relevance and priority.
- Extracts Entities. Identifies people, places, concepts and adds to knowledge graph.
- Indexes for Search. Adds to BM25 index for keyword matching alongside vectors.
- Detects Conflicts. When using /process, checks for conflicting memories and automatically updates or removes outdated information.
