Authentication
All API requests require a Bearer token in the Authorization header. Generate API keys from your dashboard.
Authorization: Bearer rec_live_<your_api_key>
# Example curl
curl https://api.retainr.dev/v1/memories/search \
-H "Authorization: Bearer rec_live_abc123..." \
-G --data-urlencode "query=customer preferences" \
--data-urlencode "user_id=usr_42"Key format: API keys start with rec_live_ followed by 32 base58 characters. Store them in environment variables - never hardcode in workflow nodes.
Quick start - 2 API calls to memory
The core loop is: store what your agent learns, search for relevant context before responding. Nothing else required.
// POST https://api.retainr.dev/v1/memories
{
"content": "Customer is price-sensitive, prefers email over phone calls",
"user_id": "usr_42",
"tags": ["preference", "contact-method"]
}// GET https://api.retainr.dev/v1/memories/search
// ?query=how+should+I+contact+this+customer
// &user_id=usr_42
// &limit=5
// Response
{
"memories": [
{
"id": "mem_8xKp2...",
"content": "Customer is price-sensitive, prefers email over phone calls",
"score": 0.94,
"tags": ["preference", "contact-method"],
"created_at": "2026-03-10T09:00:00Z"
}
]
}Store a memory
/v1/memoriesEmbed and store a memory entry for a user, session, or agent scopeRequest body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The text to embed and store. Max 8,000 characters. |
user_id | string | Yes* | Identifies the end user. Required unless session_id is set. |
session_id | string | No | Scopes memory to a single session. Auto-expires when TTL lapses. |
agent_id | string | No | Identifies the agent storing the memory. Useful for multi-agent workflows. |
namespace | string | No | Logical grouping key, e.g. 'customer:acme' or 'workflow:invoicing'. Enables multi-tenant isolation. |
tags | string[] | No | Up to 10 tags for filtering. E.g. ['preference', 'support']. |
ttl_hours | number | No | Hours until this memory auto-deletes. Omit for permanent storage. |
dedup_threshold | number | No | Cosine similarity threshold (0–1). If a memory with ≥ this score already exists in the same scope, it is updated instead of creating a duplicate. Omit to always insert. |
Example request
{
"content": "Customer opened a refund ticket for order #8821. Issue: wrong size delivered.",
"user_id": "usr_42",
"session_id": "sess_support_abc",
"namespace": "customer:acme",
"tags": ["support", "refund", "order-issue"],
"ttl_hours": 720,
"dedup_threshold": 0.92
}Response - 201 Created (new) / 200 OK (deduplicated)
{
"id": "mem_8xKp2mQ4nR...",
"content": "Customer opened a refund ticket for order #8821. Issue: wrong size delivered.",
"user_id": "usr_42",
"session_id": "sess_support_abc",
"namespace": "customer:acme",
"tags": ["support", "refund", "order-issue"],
"expires_at": "2026-04-10T09:00:00Z",
"created_at": "2026-03-10T09:00:00Z",
"deduplicated": false
}Search memories
/v1/memories/searchSemantic similarity search - returns memories ranked by meaning, not keyword overlapQuery parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural language query. E.g. 'what does this customer prefer?' |
user_id | string | Yes* | Filter to memories for this user. Required unless session_id is set. |
session_id | string | No | Restrict search to a single session scope. |
agent_id | string | No | Restrict search to memories stored by a specific agent. |
namespace | string | No | Restrict search to a namespace, e.g. 'customer:acme'. |
tags | string | No | Comma-separated tag filter. Only memories with ALL tags are returned. |
limit | number | No | Max memories to return. Default: 5. Max: 20. |
min_score | number | No | Minimum cosine similarity threshold (0-1). Default: 0.7. |
Example request
GET /v1/memories/search?query=how+should+I+approach+this+customer&user_id=usr_42&limit=3&tags=preferenceResponse - 200 OK
{
"memories": [
{
"id": "mem_8xKp2mQ4nR...",
"content": "Customer is price-sensitive, prefers email over phone calls",
"score": 0.94,
"tags": ["preference", "contact-method"],
"created_at": "2026-03-10T09:00:00Z"
},
{
"id": "mem_3fLm9nB2kS...",
"content": "Customer prefers concise replies - skip long explanations",
"score": 0.87,
"tags": ["preference"],
"created_at": "2026-03-09T14:22:00Z"
}
],
"count": 2
}List memories
/v1/memoriesPaginated list of all memories in your workspace with optional filtersQuery parameters
| Parameter | Type | Description |
|---|---|---|
user_id | string | Filter to memories for a specific user. |
session_id | string | Filter to a single session. |
scope | string | Filter by scope: user, session, agent, or global. |
namespace | string | Filter by namespace, e.g. 'customer:acme'. |
tags | string | Comma-separated. Returns memories containing ALL specified tags. |
limit | number | Page size. Default: 20. Max: 100. |
offset | number | Number of records to skip. Default: 0. |
Response - 200 OK
{
"memories": [
{
"id": "mem_8xKp2mQ4nR...",
"content": "Customer is price-sensitive, prefers email",
"scope": "user",
"user_id": "usr_42",
"namespace": "customer:acme",
"tags": ["preference"],
"created_at": "2026-03-10T09:00:00Z"
}
],
"total": 47,
"limit": 20,
"offset": 0
}Build context window
/v1/memories/contextRetrieve relevant memories pre-formatted for injection into an AI system promptThe context endpoint does the semantic search and formats the result as ready-to-inject text. Paste the returned context string directly into your LLM's system prompt.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | The current user message or topic to retrieve context for. |
user_id | string | Yes* | Retrieve memories for this user. |
session_id | string | No | Restrict to a session scope. |
agent_id | string | No | Restrict to a specific agent. |
namespace | string | No | Restrict to a namespace. |
tags | string[] | No | Only include memories with these tags. |
limit | number | No | Max memories to include. Default: 5. Max: 20. |
threshold | number | No | Min similarity score (0–1). Default: 0.6. |
format | string | No | Output format: system_prompt (default), bullet_list, or numbered_list. |
Example request
{
"query": "How should I greet this customer?",
"user_id": "usr_42",
"limit": 5,
"format": "system_prompt"
}Response - 200 OK
{
"context": "User context (3 memories):\n- Customer is price-sensitive, prefers email over phone calls (4 days ago)\n- Opened refund ticket for order #8821 (2 days ago)\n- Resolved: issued full refund (1 day ago)",
"memories_used": 3,
"token_estimate": 48
}Tip: Prepend the context string to your LLM's system prompt. Use token_estimate to stay within model context limits. The system_prompt format produces the most natural results.
Export memories
/v1/memories/exportDownload all workspace memories as a JSONL file — for backups, audits, or migrationsReturns a application/x-ndjson stream with one JSON object per line. Accepts the same filters as GET /v1/memories. Embedding vectors are never included in the export.
Example request
# Download full workspace export
curl https://api.retainr.dev/v1/memories/export \
-H "Authorization: Bearer rec_live_..." \
-o memories.jsonl
# Export only a specific namespace
curl "https://api.retainr.dev/v1/memories/export?namespace=customer:acme" \
-H "Authorization: Bearer rec_live_..." \
-o acme_memories.jsonlResponse format (JSONL)
{"id":"mem_8xKp2...","content":"Customer prefers email","scope":"user","user_id":"usr_42","namespace":"customer:acme","tags":["preference"],"created_at":"2026-03-10T09:00:00Z"}
{"id":"mem_3fLm9...","content":"Opened refund ticket for order #8821","scope":"user","user_id":"usr_42","namespace":"customer:acme","tags":["support"],"created_at":"2026-03-08T14:22:00Z"}Delete memories
/v1/memoriesBulk-delete memories by user, session, or tags - scoped to your workspaceAll deletes are scoped to your workspace. You cannot delete memories belonging to another workspace. Deletion is permanent and immediate - no soft deletes.
Request body
| Field | Type | Description |
|---|---|---|
user_id | string | Delete all memories for this user. At least one filter is required. |
session_id | string | Delete all memories in this session. |
namespace | string | Delete all memories in a namespace, e.g. 'customer:acme'. |
tags | string[] | Delete memories matching ALL specified tags. |
Example - delete all memories for a user (GDPR erasure)
{
"user_id": "usr_42"
}Response - 200 OK
{
"deleted": 14
}Rate limits
Rate limits are enforced per API key, per minute. Memory operations count against your monthly plan quota separately from per-minute limits.
| Plan | Requests/min | Memory ops/month | Max content size |
|---|---|---|---|
| Free | 30 | 1,000 | 4 KB |
| Builder | 120 | 20,000 | 8 KB |
| Pro | 300 | 100,000 | 8 KB |
| Agency | 600 | 500,000 | 16 KB |
When rate limited, the API returns 429 Too Many Requests with a Retry-After header indicating seconds to wait. n8n and Make.com modules handle retry automatically.
Error codes
All errors return a JSON body with error and message fields.
| Status | Error code | Meaning & resolution |
|---|---|---|
| 400 | invalid_request | Malformed JSON or missing required fields. Check the request body against the schema above. |
| 401 | unauthorized | Missing or invalid API key. Check your Authorization header. |
| 403 | forbidden | Your API key doesn't have access to this workspace. |
| 404 | not_found | The requested memory does not exist. |
| 422 | content_too_large | Content exceeds the per-plan character limit. Summarize or chunk the content. |
| 429 | rate_limited | Exceeded per-minute or monthly quota. Check Retry-After header and upgrade if needed. |
| 500 | internal_error | Unexpected server error. We log all 500s automatically. If it persists, open a support ticket. |
| 503 | embedding_unavailable | Embedding provider temporarily unavailable. Retry with exponential backoff. |
Platform quick starts
n8n
Install the official retainr community node. In n8n, go to Settings - Community Nodes - Install and enter n8n-nodes-retainr. Available operations: Store Memory, Search Memory, Delete Memory.
// n8n - Store Memory node (JSON body)
{
"content": "{{ $json.message }}",
"user_id": "{{ $json.userId }}",
"tags": ["{{ $json.intent }}"]
}
// n8n - Search Memory node (before your AI Call node)
{
"query": "{{ $json.userMessage }}",
"user_id": "{{ $json.userId }}",
"limit": 5
}
// Output: $json.memories - inject into your system promptMake.com
Coming soonThe native Make.com app is in review. Until it launches, use the HTTP module to call retainr's REST API directly — it works identically and takes about 2 minutes to set up.
Want to be notified when it launches? Create a free account and we'll email you.
Zapier
Coming soonThe official Zapier app is in development. In the meantime, use Webhooks by Zapier (available on all paid Zapier plans) to call retainr's REST API — POST to store, GET to search.
Want to be notified when it launches? Create a free account and we'll email you.
Ready to add memory to your workflows?
Free plan includes 1,000 memory ops per month. No credit card required.
Create free account