Quickstart
Add your first memory and ask a question in 60 seconds. Python, TypeScript, and curl code samples.
Quickstart
You'll have memory working in under a minute. This guide adds one fact, searches it back, gets a synthesized answer — and explains exactly what's happening at each step.
Get an API key
Sign in to the MemHQ dashboard and create a project. From Settings → API Keys, generate a project key and copy it.
export MEMHQ_API_KEY="mhq_live_..."Project keys are scoped to a single project and authorize the
/v1/memhq/* endpoints. Keep them server-side — they grant write
access to memory.
Install the SDK
pip install memhqnpm install @memhq/sdk
# or: pnpm add @memhq/sdk
# or: yarn add @memhq/sdkNo SDK needed — curl works against https://api.memhq.ai directly.
Add a memory
Memories belong to a user_id (per-user graph) or a group_id (shared
graph). We'll use a per-user graph here.
from memhq import MemoryClient
client = MemoryClient() # reads MEMHQ_API_KEY from the environment
result = client.add(
user_id="user_42",
messages=[
{"role": "user", "content": "I prefer dark roast coffee, no sugar."},
],
)
print(result)Response:
{
"episode_id": "ep_a1b2c3d4",
"status": "ingesting"
}import { MemoryClient } from "@memhq/sdk";
const client = new MemoryClient(); // reads MEMHQ_API_KEY from process.env
const result = await client.add({
userId: "user_42",
messages: [
{ role: "user", content: "I prefer dark roast coffee, no sugar." },
],
});
console.log(result);Response:
{
"episodeId": "ep_a1b2c3d4",
"status": "ingesting"
}curl https://api.memhq.ai/v1/memhq/add \
-H "Authorization: Bearer $MEMHQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_42",
"messages": [
{"role": "user", "content": "I prefer dark roast coffee, no sugar."}
]
}'Response:
{
"episode_id": "ep_a1b2c3d4",
"status": "ingesting"
}What just happened?
The call returns immediately (under 100 ms) with an episode_id. In the
background, MemHQ's extraction pipeline:
- Chunks the conversation into atomic units
- Extracts typed entities and facts using an LLM — in this case,
{type: "preference", content: "Prefers dark roast coffee, no sugar"} - Writes the fact to
user_42's knowledge graph and creates a vector embedding for it
By the time the next step below runs, the fact is indexed and ready to retrieve.
Search it back
results = client.search(
user_id="user_42",
query="what coffee does the user like?",
limit=5,
)
for hit in results.memories:
print(f"{hit.score:.2f} {hit.content}")Response:
{
"memories": [
{
"id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"type": "preference",
"valid_from": "2026-06-19T00:00:00Z",
"valid_until": null
}
],
"total": 1
}const results = await client.search({
userId: "user_42",
query: "what coffee does the user like?",
limit: 5,
});
for (const hit of results.memories) {
console.log(`${hit.score.toFixed(2)} ${hit.content}`);
}Response:
{
"memories": [
{
"id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"type": "preference",
"validFrom": "2026-06-19T00:00:00Z",
"validUntil": null
}
],
"total": 1
}curl https://api.memhq.ai/v1/memhq/search \
-H "Authorization: Bearer $MEMHQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_42",
"query": "what coffee does the user like?",
"limit": 5
}'Response:
{
"memories": [
{
"id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"type": "preference",
"valid_from": "2026-06-19T00:00:00Z",
"valid_until": null
}
],
"total": 1
}What just happened?
search runs three retrieval lanes in parallel — BM25 keyword, vector
similarity, and graph traversal — then merges the results with Reciprocal
Rank Fusion. The score (0–1) reflects combined relevance across all
three lanes. valid_until: null means the fact is currently true (no
contradiction has overridden it yet).
Ask a synthesized question
For agent-style Q&A, skip search and go straight to ask. MemHQ
retrieves, synthesizes, and returns an answer with citations in a single
call — no LLM invocation needed on your side.
answer = client.ask(
user_id="user_42",
question="If I'm making them coffee, how should I prepare it?",
)
print(answer.answer)
# → "Brew a dark roast with no sugar."
for citation in answer.citations:
print(f" [{citation.score:.2f}] {citation.content}")
# → [0.94] Prefers dark roast coffee, no sugarFull response:
{
"answer": "Brew a dark roast with no sugar.",
"citations": [
{
"memory_id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"valid_from": "2026-06-19T00:00:00Z"
}
],
"question_mode": "lookup"
}const answer = await client.ask({
userId: "user_42",
question: "If I'm making them coffee, how should I prepare it?",
});
console.log(answer.answer);
// → "Brew a dark roast with no sugar."
for (const citation of answer.citations) {
console.log(` [${citation.score.toFixed(2)}] ${citation.content}`);
}
// → [0.94] Prefers dark roast coffee, no sugarFull response:
{
"answer": "Brew a dark roast with no sugar.",
"citations": [
{
"memoryId": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"validFrom": "2026-06-19T00:00:00Z"
}
],
"questionMode": "lookup"
}curl https://api.memhq.ai/v1/memhq/ask \
-H "Authorization: Bearer $MEMHQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_42",
"question": "If I am making them coffee, how should I prepare it?"
}'Full response:
{
"answer": "Brew a dark roast with no sugar.",
"citations": [
{
"memory_id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"valid_from": "2026-06-19T00:00:00Z"
}
],
"question_mode": "lookup"
}What just happened?
ask is a convenience wrapper around the full retrieve → ground →
synthesize pipeline:
- Retrieve — same hybrid search as
search, returning the top-k memories - Ground — memories are packed into a grounding prompt: "Answer ONLY using these facts. Cite each one."
- Synthesize — an LLM generates the answer, tagging each claim with the memory ID it came from
question_mode: "lookup" means MemHQ classified this as a factual
retrieval question. Other modes are aggregate (counting questions) and
temporal (questions about what was true at a specific time).
Complete working example
Here's the full script from this guide in one place:
import time
from memhq import MemoryClient
client = MemoryClient() # MEMHQ_API_KEY from environment
# 1. Add a fact
client.add(
user_id="user_42",
messages=[
{"role": "user", "content": "I prefer dark roast coffee, no sugar."},
],
)
# Give the async extraction pipeline a moment to finish
time.sleep(3)
# 2. Search it back
results = client.search(
user_id="user_42",
query="coffee preference",
limit=5,
)
for hit in results.memories:
print(f"search {hit.score:.2f} {hit.content}")
# 3. Ask a synthesized question
answer = client.ask(
user_id="user_42",
question="If I'm making them coffee, how should I prepare it?",
)
print(f"ask {answer.answer}")
for c in answer.citations:
print(f" [{c.score:.2f}] {c.content}")import { MemoryClient } from "@memhq/sdk";
const client = new MemoryClient(); // MEMHQ_API_KEY from process.env
// 1. Add a fact
await client.add({
userId: "user_42",
messages: [
{ role: "user", content: "I prefer dark roast coffee, no sugar." },
],
});
// Give the async extraction pipeline a moment to finish
await new Promise((r) => setTimeout(r, 3000));
// 2. Search it back
const results = await client.search({
userId: "user_42",
query: "coffee preference",
limit: 5,
});
for (const hit of results.memories) {
console.log(`search ${hit.score.toFixed(2)} ${hit.content}`);
}
// 3. Ask a synthesized question
const answer = await client.ask({
userId: "user_42",
question: "If I'm making them coffee, how should I prepare it?",
});
console.log(`ask ${answer.answer}`);
for (const c of answer.citations) {
console.log(` [${c.score.toFixed(2)}] ${c.content}`);
}The time.sleep(3) / setTimeout(3000) is only needed in scripts where
you add and immediately search in the same run. In production, facts
are added during one conversation turn and searched in the next — the
async extraction window is invisible.
Where to go next
- Memory API reference — the full shape of
add,search, andask - How it Works — the ingest pipeline, knowledge graph, and hybrid retrieval explained with code
- Cookbook: Chatbot with memory — wire MemHQ into a complete chat loop
- SDKs — language-specific guides and configuration