Introduction
Memra gives your AI app a memory. When a user talks to your AI, Memra saves the conversation. Next time that user comes back, your AI remembers what they said — their name, preferences, what they were working on. Everything.
How it works in 30 seconds:
- User says “My name is Wais” → your AI replies → Memra saves both messages
- User comes back tomorrow, asks “What's my name?”
- Your app calls
memory.getContext()→ gets back “My name is Wais” - You put that in the system prompt → AI answers “Your name is Wais!”
Save
After each AI response, save the exchange with memory.save(). Two lines of code.
Retrieve
Before the next response, call memory.getContext(). It returns recent chat + relevant older memories.
Inject
Put the memories in your system prompt. Your AI now remembers everything.
Installation
Install the Memra client package. Works with any JavaScript/TypeScript project — Next.js, Express, anything.
npm install @memra-client/clientThen get your API key from the dashboard (starts with mk_mem_).
Quick start
This is all you need. Four steps: create the client, get context, call your AI, save the exchange.
import { MemoryClient } from '@memra-client/client'
const memory = new MemoryClient({ apiKey: 'mk_mem_...' })
export async function chat(userId: string, userMessage: string) {
// 1. Get recent conversation + relevant older memories
const { recentHistory, relevantMemories } = await memory.getContext(
userId,
userMessage
)
// 2. Build a system prompt that includes BOTH
let memoryText = ''
if (recentHistory.length > 0) {
memoryText += 'Recent conversation:\n'
memoryText += recentHistory
.map(m => `[${m.role}]: ${m.content}`)
.join('\n')
memoryText += '\n\n'
}
if (relevantMemories.length > 0) {
memoryText += 'Relevant older memories:\n'
memoryText += relevantMemories
.map(m => `[${m.role}]: ${m.content}`)
.join('\n')
}
const systemPrompt = memoryText
? `You are a helpful assistant with memory.
${memoryText}
Use this to give personalized responses.`
: 'You are a helpful assistant.'
// 3. Call your AI provider (works with any: OpenAI, Groq, etc.)
const aiReply = await yourAI.chat.completions.create({
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage },
],
})
// 4. Save this exchange so AI remembers it next time
await memory.save(userId, userMessage, aiReply)
return aiReply
}💡 Tip
recentHistory gives the AI the last 10 messages in order — so it always knows the recent conversation. relevantMemoriesgives it related messages from older chats. Together they fix the “what's my name?” problem.Full working example
A complete Next.js API route you can copy-paste. This is exactly how the demo works.
// Complete working example — Next.js API route
import { NextResponse } from 'next/server'
import MemoryClient from '@memra-client/client'
const memory = new MemoryClient({
apiKey: process.env.MEMRA_API_KEY || '',
})
export async function POST(req: Request) {
const { query } = await req.json()
// Step 1: Get memories (recent chat + relevant older ones)
const { recentHistory, relevantMemories } = await memory.getContext(
'user_123', query, { limit: 5, recentLimit: 10 }
)
// Step 2: Build the system prompt
let memorySection = ''
if (recentHistory.length > 0) {
memorySection += 'Recent conversation:\n'
+ recentHistory.map(m => `[${m.role}]: ${m.content}`).join('\n')
+ '\n\n'
}
if (relevantMemories.length > 0) {
memorySection += 'Relevant older memories:\n'
+ relevantMemories.map(m => `[${m.role}]: ${m.content}`).join('\n')
}
const systemPrompt = memorySection
? `You are a helpful assistant with memory.\n${memorySection}\nUse ALL of this to answer.`
: 'You are a helpful assistant.'
// Step 3: Call any AI provider
const aiResponse = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: query },
],
}),
})
const data = await aiResponse.json()
const reply = data.choices[0].message.content
// Step 4: Save so AI remembers next time
await memory.save('user_123', query, reply)
return NextResponse.json({ reply })
}MemoryClient
Create one instance and reuse it. Don't create a new one for every request.
Constructor
import { MemoryClient } from '@memra-client/client'
const memory = new MemoryClient({
apiKey: 'mk_mem_...', // required — from your dashboard
baseUrl: 'https://memra-rho.vercel.app/api' // optional — this is the default
})Options
| Parameter | Type | Description |
|---|---|---|
| apiKeyreq | string | Your Memory API key from the dashboard. Starts with mk_mem_ |
| baseUrl | string | API base URL. Default: https://memra-rho.vercel.app/api |
POST /memory/savememory.save()
Call this after every AI response. It saves both the user message and AI reply to memory. Each message gets turned into a vector embedding so it can be found later with semantic search.
Signature
memory.save(
userId: string, // your end-user's identifier
userMessage: string, // the user's message text
aiReply: string, // the assistant's response text
options?: {
agentId?: string // isolate memory per bot or context (default: 'default')
}
): Promise<{ success: boolean; saved: number }>Parameters
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | Your user's ID. Each user gets their own isolated memory — they can't see each other's data. |
| userMessagereq | string | What the user said. |
| aiReplyreq | string | What your AI replied. |
| options.agentId | string | If your app has multiple bots (e.g. support-bot, coding-bot), use this to keep their memories separate. Default: 'default' |
Example
// After your AI replies, save the exchange
const result = await memory.save(
'user_abc123',
'What is my current plan?',
'You are on the Free plan — 500 memory slots available.',
{ agentId: 'support-bot' }
)
// => { success: true, saved: 2 }GET /memory/contextmemory.getContext()
This is the most important method. Call it before every AI response. It returns two things:
recentHistory
The last 10 messages in chronological order. The AI always knows what was just said.
relevantMemories
Semantically similar messages from older conversations. Found via vector search.
Signature
memory.getContext(
userId: string,
query: string, // the current message — used for semantic search
options?: {
agentId?: string // filter to a specific agent (default: 'default')
limit?: number // max semantic results (default: 5)
recentLimit?: number // max recent messages (default: 10)
}
): Promise<ContextResponse>Parameters
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | The user whose memories to search. |
| queryreq | string | The current user message. Used to find related older memories. |
| options.agentId | string | Filter to a specific bot's memories. Default: 'default' |
| options.limit | number | How many semantic results to return. Default: 5 |
| options.recentLimit | number | How many recent messages to return. Default: 10 |
Response types
interface ContextResponse {
recentHistory: Memory[] // last N messages chronologically
relevantMemories: Memory[] // semantic matches from older conversations
context: Memory[] // backwards compat — same as semantic results
count: number
latencyMs: number // end-to-end latency, added client-side
}
interface Memory {
id: string
content: string
role: 'user' | 'assistant'
createdAt: string
similarity?: number // 0–1 cosine score (only on semantic results)
}Example
// This is the key method — call it before every AI response
const { recentHistory, relevantMemories } = await memory.getContext(
'user_abc123',
'What plan am I on?',
{ limit: 5, recentLimit: 10 }
)
// recentHistory = last 10 messages in order (always includes recent chat)
// relevantMemories = semantically similar older messages (deduplicated)
// Use BOTH in your system prompt:
const systemPrompt = `You remember everything.
Recent: ${recentHistory.map(m => m.content).join(' | ')}
Related: ${relevantMemories.map(m => m.content).join(' | ')}`⚠️ Warning
GET /memory/historymemory.getHistory()
Returns the complete chat history for a user — every message they ever sent and received. Use this to show past conversations in your UI. You don't need your own database for chat storage — Memra stores it all.
Signature
memory.getHistory(
userId: string,
options?: {
agentId?: string // filter by agent (omit = all agents)
limit?: number // omit to get ALL messages
order?: 'asc'|'desc' // default: 'asc' (oldest first)
before?: string // ISO date — get messages before this time
after?: string // ISO date — get messages after this time
}
): Promise<{
history: Memory[] // every message for this user
total: number // total message count
count: number // messages in this response
}>Parameters
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | The user whose history to fetch. |
| options.agentId | string | Filter by bot. Omit to get all bots' messages together. |
| options.limit | number | Omit to get ALL messages. Set a number to limit. |
| options.order | 'asc' | 'desc' | 'asc' = oldest first (default, good for chat UI). 'desc' = newest first. |
| options.before | string | ISO date. Get messages before this time (for pagination). |
| options.after | string | ISO date. Get messages after this time (for pagination). |
Example
// Get ALL chat history for a user (for showing in your UI)
const { history, total } = await memory.getHistory('user_abc123')
console.log('Total messages stored:', total)
history.forEach(m => {
console.log('[' + m.role + '] ' + m.content)
})
// With filters:
const recent = await memory.getHistory('user_abc123', {
agentId: 'support-bot',
order: 'desc', // newest first
limit: 20, // just the last 20
})Real-world usage — API route for chat history
Create an API route in your app that fetches a user's complete chat history. Your frontend calls this to display past conversations — like a chat sidebar or message list.
// app/api/history/route.ts — API route to fetch chat history
import { NextResponse } from 'next/server'
import MemoryClient from '@memra-client/client'
const client = new MemoryClient({
apiKey: process.env.MEMRA_API_KEY || '',
})
export async function GET() {
// Returns ALL messages for this user, oldest first
const { history, total } = await client.getHistory('user_123', {
order: 'asc',
})
return NextResponse.json({ history, total })
}
// Then in your frontend:
// const res = await fetch('/api/history')
// const { history, total } = await res.json()
// history.forEach(msg => renderMessage(msg.role, msg.content))💡 Tip
save(). Call getHistory() to get them all back — sorted, filtered, and ready to display. Use getContext() separately before AI responses to inject the right memories into the prompt.DELETE /memory/forgetmemory.forget()
Permanently deletes memories. Use this for GDPR compliance, when a user asks to be forgotten, or when you want to start fresh. This cannot be undone.
Signature
memory.forget(
userId: string,
options?: {
agentId?: string // omit to delete ALL memories for this user
}
): Promise<{ success: boolean; deleted: number }>Parameters
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | The user whose memories to delete. |
| options.agentId | string | Only delete this bot's memories. Omit to delete ALL memories for this user. |
Example
// Clear only this agent's memory
await memory.forget('user_abc123', { agentId: 'support-bot' })
// Clear ALL memories for a user across every agent
const result = await memory.forget('user_abc123')
// => { success: true, deleted: 124 }REST API
Don't want to use the npm package? Call the API directly with curl, Python, Go — any language. All endpoints need your API key in the x-api-key header.
Base URL
https://memra-rho.vercel.app/api
| Method | Endpoint | Description |
|---|---|---|
| POST | /memory/save | Save a user message + AI reply |
| GET | /memory/context | Get recent chat + relevant older memories |
| GET | /memory/history | Get complete chat history for a user |
| DELETE | /memory/forget | Delete memories |
POST /memory/save
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | Your user's ID. |
| userMessagereq | string | What the user said. |
| aiReplyreq | string | What the AI replied. |
| agentId | string | Bot namespace. Default: 'default' |
curl -X POST https://memra-rho.vercel.app/api/memory/save \
-H 'Content-Type: application/json' \
-H 'x-api-key: mk_mem_...' \
-d '{
"userId": "user_123",
"userMessage": "What is my plan?",
"aiReply": "You are on the Free plan.",
"agentId": "support-bot"
}'{ "success": true, "saved": 2 }GET /memory/context
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | User to search. |
| queryreq | string | The search query. |
| agentId | string | Filter by bot. Default: 'default' |
| limit | number | Max semantic results. Default: 5 |
| recentLimit | number | Max recent messages. Default: 10 |
curl 'https://memra-rho.vercel.app/api/memory/context?userId=user_123&query=account+plan&limit=5&recentLimit=10' \
-H 'x-api-key: mk_mem_...'{
"recentHistory": [
{ "id": "clx1", "content": "What is my plan?", "role": "user", "createdAt": "..." },
{ "id": "clx2", "content": "You are on Free.", "role": "assistant", "createdAt": "..." }
],
"relevantMemories": [
{ "id": "clx0", "content": "I signed up yesterday", "role": "user", "similarity": 0.72 }
],
"context": [...],
"count": 1
}GET /memory/history
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | User whose history to fetch. |
| agentId | string | Filter by bot. Omit for all. |
| limit | number | Omit to get ALL messages. |
| order | 'asc'|'desc' | Default: asc (oldest first). |
| before | string | ISO date for pagination. |
| after | string | ISO date for pagination. |
# Get ALL messages for a user (no limit)
curl 'https://memra-rho.vercel.app/api/memory/history?userId=user_123' \
-H 'x-api-key: mk_mem_...'
# With pagination
curl 'https://memra-rho.vercel.app/api/memory/history?userId=user_123&limit=20&order=desc' \
-H 'x-api-key: mk_mem_...'{
"history": [
{ "id": "clx1", "content": "Hello", "role": "user", "createdAt": "..." },
{ "id": "clx2", "content": "Hi! How can I help?", "role": "assistant", "createdAt": "..." }
],
"total": 142,
"count": 142
}DELETE /memory/forget
| Parameter | Type | Description |
|---|---|---|
| userIdreq | string | User whose memories to delete. |
| agentId | string | Delete only this bot's memories. Omit to delete everything. |
curl -X DELETE https://memra-rho.vercel.app/api/memory/forget \
-H 'Content-Type: application/json' \
-H 'x-api-key: mk_mem_...' \
-d '{ "userId": "user_123", "agentId": "support-bot" }'{ "success": true, "deleted": 14 }Error codes
When something goes wrong, the API returns a JSON object with an error field. The SDK throws an error automatically — wrap calls in try/catch.
| Status | What went wrong | How to fix |
|---|---|---|
| 400 | Missing required field | Check that you're sending userMessage, aiReply, query, etc. |
| 401 | Bad API key | Check your mk_mem_ key is correct and active in the dashboard. |
| 403 | Wrong key type | You're using an extension key (mk_ext_) on a memory endpoint. Use mk_mem_ instead. |
| 429 | Memory limit reached | Your plan's storage is full. Delete old memories or upgrade. |
429 — Limit reached
{
"error": "Memory limit reached",
"limit": 100,
"plan": "free",
"upgrade": "https://memra-rho.vercel.app/pricing"
}