Users + threads
Bring your own externalId. Creating a user auto-creates their user graph. Append messages to a thread, get auto-ingest for free.
Authentication
Same Bearer-token auth as the rest of the API. All endpoints are scoped to the project the key belongs to.
Authorization: Bearer mos_live_xxxxxxxxxxxxxxxxxxxx
/v1/usersCreate a user and atomically materialize their user graph.
Request
interface CreateUserRequest {
externalId?: string; // your id for this user
email?: string;
firstName?: string;
lastName?: string;
metadata?: Record<string, unknown>;
}Response (201)
{
"id": "usr_01HXY...",
"externalId": "user_clerk_abc",
"email": "[email protected]",
"firstName": "Alice", "lastName": null,
"graphId": "grph_01HXY...",
"createdAt": "2026-05-17T12:00:00Z"
}Curl
curl -X POST "$MEMOS_URL/v1/users" \
-H "Authorization: Bearer $MEMOS_KEY" \
-H "Content-Type: application/json" \
-d '{ "externalId": "user_clerk_abc", "email": "[email protected]" }'Duplicate handling
externalId returns 409 with codeUSER_EXISTS and includes the existing id, so you can safely treat the call as idempotent in your app./v1/usersList users in the project with thread + memory counts.
{
"users": [
{
"id": "usr_...",
"externalId": "user_clerk_abc",
"email": "[email protected]",
"graphId": "grph_...",
"stats": { "threads": 3, "memories": 47 },
"createdAt": "2026-05-17T12:00:00Z"
}
]
}/v1/users/:idGet one user with full stats and the biographical summary.
{
"id": "usr_...",
"externalId": "user_clerk_abc",
"email": "[email protected]",
"summary": "Senior platform engineer at Acme. Joined 2023, on the billing team.",
"graphId": "grph_...",
"stats": { "threads": 3, "memories": 47, "entities": 23 },
"createdAt": "..."
}/v1/users/:idDelete a user. Cascades through the user's graph, threads, messages, every derived memory + entity + relation. Audit-logged.
{ "deleted": true, "id": "usr_..." }/v1/users/:id/graphDiagnostic: get the graphId for this user.
{
"userId": "usr_...",
"graphId": "grph_...",
"createdAt": "...",
"stats": { "memories": 47 }
}/v1/users/:id/contextReturns a paste-ready system-prompt block. Covered in the Memory API reference; copied here for discoverability.
Query params
template—chat,agent,supportmaxTokens— default 1500, max 8000groups— comma-separated names to merge in
/v1/users/:id/summaryRegenerate the user's biographical summary. Idempotent unless ?force=true.
{
"generated": true,
"summary": "Senior platform engineer at Acme...",
"memoryCount": 47
}/v1/users/:id/threadsCreate a conversation thread.
// Request
{ "name": "Onboarding chat" }
// Response (201)
{
"id": "thr_...",
"name": "Onboarding chat",
"userId": "usr_...",
"createdAt": "..."
}/v1/users/:id/threadsList a user's threads with message counts.
/v1/threads/:id/messagesAppend a message (or array of messages). User-role messages are auto-ingested into the user's graph. Assistant / system / tool messages are stored but not extracted as facts.
Request
// Single message
{ "role": "user", "content": "I prefer dark mode." }
// Or batched
{
"messages": [
{ "role": "user", "content": "Tell me about my invoices." },
{ "role": "assistant", "content": "You have 3 unpaid invoices..." }
]
}Response (201)
{
"threadId": "thr_...",
"messages": [
{ "id": "msg_...", "role": "user", "content": "...", "createdAt": "..." }
],
"ingested": [
{ "messageId": "msg_...", "jobId": "ij_..." }
]
}/v1/threads/:id/messagesReplay a thread.
{
"thread": { "id": "thr_...", "name": "Onboarding chat", "userId": "usr_..." },
"messages": [
{ "id": "msg_...", "role": "user", "content": "...", "createdAt": "..." }
]
}Patterns
Most chat apps map cleanly onto users + threads + messages. When a new chat window opens, call POST /v1/users/:id/threads for a fresh threadId. On each turn, append the user message — the worker handles extraction and graph writes. Use /v1/users/:id/context at session start to prime your system prompt.