API reference

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
POST/v1/users

Create 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

Re-creating with the same externalId returns 409 with codeUSER_EXISTS and includes the existing id, so you can safely treat the call as idempotent in your app.
GET/v1/users

List 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"
    }
  ]
}
GET/v1/users/:id

Get 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": "..."
}
DELETE/v1/users/:id

Delete a user. Cascades through the user's graph, threads, messages, every derived memory + entity + relation. Audit-logged.

{ "deleted": true, "id": "usr_..." }
GET/v1/users/:id/graph

Diagnostic: get the graphId for this user.

{
  "userId": "usr_...",
  "graphId": "grph_...",
  "createdAt": "...",
  "stats": { "memories": 47 }
}
GET/v1/users/:id/context

Returns a paste-ready system-prompt block. Covered in the Memory API reference; copied here for discoverability.

Query params

  • templatechat, agent, support
  • maxTokens — default 1500, max 8000
  • groups — comma-separated names to merge in
POST/v1/users/:id/summary

Regenerate the user's biographical summary. Idempotent unless ?force=true.

{
  "generated": true,
  "summary": "Senior platform engineer at Acme...",
  "memoryCount": 47
}
POST/v1/users/:id/threads

Create a conversation thread.

// Request
{ "name": "Onboarding chat" }

// Response (201)
{
  "id": "thr_...",
  "name": "Onboarding chat",
  "userId": "usr_...",
  "createdAt": "..."
}
GET/v1/users/:id/threads

List a user's threads with message counts.

POST/v1/threads/:id/messages

Append 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_..." }
  ]
}
GET/v1/threads/:id/messages

Replay 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.