> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usesatori.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Memory

> Save a new memory to the database

## `memory.add`

Saves a new memory with automatic embedding generation for semantic search.

## Parameters

<ParamField body="userId" type="string" required>
  User identifier for memory isolation. Must be a stable, unique ID for each user.

  ```typescript theme={null}
  userId: 'user-123'
  ```
</ParamField>

<ParamField body="content" type="string" required>
  The text content to save. Should be a complete, self-contained statement.

  ```typescript theme={null}
  content: 'User prefers TypeScript over JavaScript for type safety'
  ```

  <Tip>
    Write memories as complete sentences that make sense out of context.
  </Tip>
</ParamField>

<ParamField body="metadata" type="object">
  Optional metadata for categorization and filtering.

  ```typescript theme={null}
  metadata: {
    category: 'preference',
    tags: ['programming', 'languages'],
    importance: 'high',
    customField: 'value'
  }
  ```
</ParamField>

## Response

<ResponseField name="id" type="string" required>
  Unique identifier (UUID) for the memory
</ResponseField>

<ResponseField name="content" type="string" required>
  The saved text content
</ResponseField>

<ResponseField name="userId" type="string" required>
  User identifier
</ResponseField>

<ResponseField name="clerkUserId" type="string" required>
  Tenant identifier (API key owner)
</ResponseField>

<ResponseField name="metadata" type="object">
  Custom metadata object
</ResponseField>

<ResponseField name="createdAt" type="string" required>
  ISO 8601 timestamp of creation
</ResponseField>

<ResponseField name="updatedAt" type="string" required>
  ISO 8601 timestamp of last update
</ResponseField>

## Examples

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { createTRPCClient, httpBatchLink } from '@trpc/client';
  import type { AppRouter } from '@satori/server';

  const client = createTRPCClient<AppRouter>({
    links: [
      httpBatchLink({
        url: 'https://api.usesatori.sh/trpc',
        headers: {
          'x-api-key': process.env.SATORI_API_KEY!,
        },
      }),
    ],
  });

  const memory = await client.memory.add.mutate({
    userId: 'user-123',
    content: 'User prefers dark mode in all applications',
    metadata: {
      category: 'preference',
      tags: ['ui', 'theme'],
    },
  });

  console.log('Memory saved:', memory.id);
  ```

  ```javascript JavaScript theme={null}
  const memory = await client.memory.add.mutate({
    userId: 'user-123',
    content: 'User prefers dark mode in all applications',
    metadata: {
      category: 'preference',
      tags: ['ui', 'theme'],
    },
  });
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.usesatori.sh/trpc/memory.add' \
    -H 'x-api-key: sk_satori_...' \
    -H 'Content-Type: application/json' \
    -d '{
      "userId": "user-123",
      "content": "User prefers dark mode in all applications",
      "metadata": {
        "category": "preference",
        "tags": ["ui", "theme"]
      }
    }'
  ```
</CodeGroup>

<RequestExample>
  ```json Request theme={null}
  {
    "userId": "user-123",
    "content": "User prefers TypeScript over JavaScript for type safety",
    "metadata": {
      "category": "preference",
      "tags": ["programming", "languages"],
      "importance": "high"
    }
  }
  ```
</RequestExample>

<ResponseExample>
  ```json Success (200) theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "content": "User prefers TypeScript over JavaScript for type safety",
    "userId": "user-123",
    "clerkUserId": "user_372Icb...",
    "metadata": {
      "category": "preference",
      "tags": ["programming", "languages"],
      "importance": "high"
    },
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  }
  ```

  ```json Error (401) theme={null}
  {
    "error": {
      "message": "Unauthorized - Invalid API key",
      "code": "UNAUTHORIZED"
    }
  }
  ```

  ```json Error (400) theme={null}
  {
    "error": {
      "message": "Invalid input: content is required",
      "code": "BAD_REQUEST"
    }
  }
  ```
</ResponseExample>

## Embedding Generation

When you save a memory, Satori automatically:

1. Sends the content to OpenAI's `text-embedding-3-small` model
2. Receives a 1536-dimensional vector
3. Stores both the text and embedding in PostgreSQL

This enables semantic search without any additional work on your part.

<Info>
  Embedding generation typically takes 50-100ms. The API call returns after the memory is fully saved with its embedding.
</Info>

## Best Practices

<AccordionGroup>
  <Accordion title="Write complete, self-contained memories">
    ```typescript theme={null}
    // ✅ Good: Complete sentence with context
    await client.memory.add.mutate({
      userId: 'user-123',
      content: 'User prefers TypeScript over JavaScript for type safety',
    });

    // ❌ Bad: Too vague
    await client.memory.add.mutate({
      userId: 'user-123',
      content: 'likes TS',
    });
    ```
  </Accordion>

  <Accordion title="Use metadata for organization">
    ```typescript theme={null}
    await client.memory.add.mutate({
      userId: 'user-123',
      content: 'User works at Acme Corp as a senior engineer',
      metadata: {
        category: 'professional',
        subcategory: 'employment',
        verified: true,
        source: 'user-provided',
      },
    });
    ```
  </Accordion>

  <Accordion title="Avoid duplicate memories">
    ```typescript theme={null}
    // Search first to avoid duplicates
    const existing = await client.memory.search.query({
      userId: 'user-123',
      query: 'TypeScript preference',
      threshold: 0.9,
    });

    if (existing.length === 0) {
      await client.memory.add.mutate({
        userId: 'user-123',
        content: 'User prefers TypeScript',
      });
    }
    ```
  </Accordion>
</AccordionGroup>

## Error Handling

```typescript theme={null}
try {
  const memory = await client.memory.add.mutate({
    userId: 'user-123',
    content: 'Important information',
  });
  
  console.log('Memory saved:', memory.id);
} catch (error) {
  if (error.message.includes('Unauthorized')) {
    console.error('Invalid API key');
  } else if (error.message.includes('rate limit')) {
    console.error('Rate limit exceeded, retry later');
  } else {
    console.error('Failed to save memory:', error);
  }
}
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Search Memories" icon="magnifying-glass" href="/api-reference/memory/search">
    Find relevant memories using semantic search
  </Card>

  <Card title="Get All Memories" icon="list" href="/api-reference/memory/get-all">
    Retrieve all memories for a user
  </Card>

  <Card title="Delete Memory" icon="trash" href="/api-reference/memory/delete">
    Remove a specific memory
  </Card>

  <Card title="Integration Guide" icon="code" href="/guides/vercel-ai-sdk">
    See this endpoint in action
  </Card>
</CardGroup>
