supermemory/apps/docs/ingestion/add-memories.mdx
MaheshtheDev 672defc08b docs: move SDK snippets to the shipped v5 call shape and finish the namespace rename (#1772)
Rewrites 339 TypeScript calls across 50 pages from the rc.5 `method({ namespace, body })` form to the shipped `method(namespace, { ... })` form, and aligns field names with the live v5 spec: `attach` to `include`, `authUrl` to `authorization`, `lastSync` to `latestRun`, `deletedCount` to `count`, and the paginated `namespaces.list()`.

Renames container tags to namespaces across concepts, connectors, integrations and snippets. The namespace pages keep container tag in the description, search keywords and a rename note so old searches still land, and the v3 reference page points at v5.

The migration guide's SDK table now covers both 5.0.0 SDKs, and the SDK integration page uses the real client options (`baseUrl`, `timeoutInSeconds`, `maxRetries`) and error classes.
2026-10-06 17:06:38 +00:00

488 lines
16 KiB
Text

---
title: "Ingesting context to supermemory"
sidebarTitle: "API"
description: "Add text, files, and URLs to Supermemory"
icon: "/icons/hugeicons/plus-sign.svg"
---
Send any raw content to Supermemory — conversations, documents, files, URLs. We extract the memories automatically. Pass `id` to identify content and avoid duplicates, and `taskType: "superrag"` if you just need it searchable, not remembered — that's [5x cheaper](#memory-vs-superrag-ingestion) per token.
Every write goes to one `namespace` (what v3/v4 called a container tag). The namespace sits in the URL path, never in the body.
## Quick start
<Tabs>
<Tab title="TypeScript">
```typescript
import { Supermemory } from "supermemory";
const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
// Add text content
await supermemory.add("user_123", {
content: "Machine learning enables computers to learn from data",
metadata: { category: "ai" },
});
// Add a URL (auto-extracted)
await supermemory.add("user_123", {
content: "https://youtube.com/watch?v=dQw4w9WgXcQ"
});
```
</Tab>
<Tab title="Python">
```python
from supermemory import Supermemory
client = Supermemory()
# Add text content
client.add(
"user_123",
content="Machine learning enables computers to learn from data",
metadata={"category": "ai"},
)
# Add a URL (auto-extracted)
client.add("user_123", content="https://youtube.com/watch?v=dQw4w9WgXcQ")
```
</Tab>
<Tab title="cURL">
```bash
curl -X POST "https://api.supermemory.ai/ns/user_123/document" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Machine learning enables computers to learn from data",
"metadata": {"category": "ai"}
}'
```
</Tab>
</Tabs>
**Response:**
```json
{ "id": "abc123", "status": "queued" }
```
<Warning>
If an irrecoverable processing error occurs, the document is automatically deleted after 2 minutes.
</Warning>
---
## Updating content
Use `id` to update existing documents or conversations. When you send content with the same `id`, Supermemory intelligently processes only what's new.
### Two ways to update:
**Option 1: Send only the new content**
```typescript
// First request
await supermemory.add("user_sarah", {
content: "user: Hi, I'm Sarah.\nassistant: Nice to meet you!",
id: "conv_123",
});
// Later: send only new messages
await supermemory.add("user_sarah", {
content: "user: What's the weather?\nassistant: It's sunny today.",
id: "conv_123", // Same ID — Supermemory links them
});
```
**Option 2: Send the full updated content**
```typescript
// Supermemory detects the diff and only processes new parts
await supermemory.add("user_sarah", {
content: "user: Hi, I'm Sarah.\nassistant: Nice to meet you!\nuser: What's the weather?\nassistant: It's sunny today.",
id: "conv_123",
});
```
Both work — choose what fits your architecture.
### Replace entire document
To completely replace a document's content (not append), use `documents.update()`:
```typescript
// Replace the entire document content
await supermemory.documents.update("user_sarah", "doc_id_123", {
content: "Completely new content replacing everything",
metadata: { version: 2 },
});
```
This triggers full reprocessing of the document. If you only update metadata (no content change), the document is updated in place with no reindexing.
### Formatting conversations
Format your conversations however you want. Supermemory handles any string format:
```typescript
// Simple string
content: "user: Hello\nassistant: Hi there!"
// JSON stringify
content: JSON.stringify(messages)
// Template literal
content: messages.map(m => `${m.role}: ${m.content}`).join('\n')
// Any format — just make it a string
content: formatConversation(messages)
```
---
## Upload files
Upload PDFs, images, and documents directly. This is a multipart request, so `metadata` is a JSON string here, not an object.
<Tabs>
<Tab title="TypeScript">
```typescript
import { openAsBlob } from "node:fs";
await supermemory.documents.uploadFile("user_123", {
file: await openAsBlob("document.pdf"),
metadata: JSON.stringify({ source: "upload" }),
});
```
</Tab>
<Tab title="Python">
```python
import json
with open("document.pdf", "rb") as file:
client.documents.upload_file(
"user_123",
file=file,
metadata=json.dumps({"source": "upload"}),
)
```
</Tab>
<Tab title="cURL">
```bash
curl -X POST "https://api.supermemory.ai/ns/user_123/document/file" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-F "file=@document.pdf" \
-F 'metadata={"source":"upload"}'
```
</Tab>
</Tabs>
### Supported file types
| Type | Formats | Processing |
|------|---------|------------|
| Documents | PDF, DOC, DOCX, TXT, MD | Text extraction, OCR for scans |
| Images | JPG, PNG, GIF, WebP | OCR text extraction |
| Spreadsheets | CSV, Google Sheets | Structured data extraction |
| Videos | YouTube URLs, MP4 | Auto-transcription |
**Limits:** 50MB max file size
<Note>
Scale and Enterprise include [advanced document extraction for PDFs](/concepts/content-types#advanced-document-extraction), with page-by-page OCR and descriptions of figures and diagrams. It is selected automatically from your organization's plan; no extra upload parameter is needed. Free, Pro, and Max keep standard PDF extraction, including OCR for scans.
</Note>
---
## Parameters
`namespace`, `taskType`, and `dreaming` are top-level keys on the SDK call (`taskType` and `dreaming` are query parameters on the HTTP route). Everything else goes in `body`.
| Parameter | Type | Description |
|-----------|------|-------------|
| `namespace` | string | **Required.** Group by user/project. Goes in the URL path. Required for user profiles |
| `content` | string | **Required.** Any raw content — text, conversations, URLs, HTML |
| `id` | string | **Recommended.** Your ID for the content (conversation ID, doc ID). Enables updates and deduplication. The response `id` echoes it back |
| `metadata` | object | Key-value pairs for filtering (strings, numbers, booleans) |
| `group` | object | Filter which existing memories are used as context during ingestion. See [Filtered Writes](#filtered-writes) |
| `supportingContext` | string | Context for memory extraction on this namespace. Max 1500 chars. See [Customization](/concepts/customization#entity-context) |
| `date` | string | ISO 8601 date the content was originally created. Use when backfilling. See [Backfill historical data](/ingestion/batch-ingest-historical-data) |
| `dreaming` | `"dynamic" \| "instant"` | Processing mode. Default `"dynamic"`. `"instant"` processes each document on its own and bills one extra operation. See [Processing Modes](#processing-modes) |
| `taskType` | `"memory" \| "superrag"` | Pipeline to run. Default `"memory"`. `"superrag"` skips fact extraction and profile updates, doing only chunk/embed/index — at 5x cheaper per token. See [SuperRAG ingestion](/concepts/super-rag#ingesting-as-pure-superrag-tasktype-superrag) |
<AccordionGroup>
<Accordion title="Parameter details & examples">
**Content Types:**
```typescript
// Any text — conversations, notes, documents
{ content: "Meeting notes from today's standup" }
{ content: JSON.stringify(messages) }
// URLs (auto-detected and extracted)
{ content: "https://example.com/article" }
{ content: "https://youtube.com/watch?v=abc123" }
// Markdown, HTML, or any format
{ content: "# Project Docs\n\n## Features\n- Real-time sync" }
```
**Namespaces:**
```typescript
// By user
{ namespace: "user_123" }
// By project
{ namespace: "project_alpha" }
// Hierarchical
{ namespace: "org_456_team_backend" }
```
**IDs (Recommended):**
```typescript
// Use IDs from your system
{ id: "conv_abc123" } // Conversation ID
{ id: "doc_456" } // Document ID
{ id: "thread_789" } // Thread ID
{ id: "meeting_2024_01_15" } // Meeting ID
// Updates: same id = same document
// Supermemory only processes new/changed content
await supermemory.add("user_123", {
content: "Updated content...",
id: "doc_456", // Links to existing document
});
```
**Metadata:**
```typescript
{
metadata: {
source: "slack",
author: "john",
priority: 1,
reviewed: true
}
}
```
- No nested objects or arrays
- Values: string, number, or boolean only
**Supporting Context:**
```typescript
// Guide memory extraction for this namespace
await supermemory.add("session_abc123", {
content: "...",
supportingContext: `Design exploration conversation between john@acme.com and Brand.ai assistant.
Focus on John's design preferences and brand requirements.`,
});
```
- Max 1500 characters
- Persists on the namespace
- Combines with org-level organizational context
</Accordion>
</AccordionGroup>
---
## Processing modes
### Dreaming: dynamic vs instant
The `dreaming` parameter controls how Supermemory turns a document into memories.
- `"dynamic"` (default) — groups related documents together so memories form from coherent, logical units rather than one isolated entry at a time. A fresh namespace can show zero memories and an empty profile for several minutes.
- `"instant"` — processes each document on its own right away, and bills one extra operation per document. Use it for quickstarts, tests, and any flow that reads memories or a profile right after `add`.
```typescript
await supermemory.add("user_123", {
content: "...",
dreaming: "instant",
});
```
### Memory vs SuperRAG ingestion
The `taskType` parameter controls whether that content also feeds the memory pipeline.
- `"memory"` (default) — chunks/embeds for search **and** extracts facts, updates the user's profile, and links into the graph.
- `"superrag"` — chunks/embeds for search only. No fact extraction, no profile updates. Priced at **5x cheaper per token** than `"memory"`.
```typescript
await supermemory.add("user_123", {
content: "...",
taskType: "superrag",
});
```
Use `"superrag"` for reference material you want searchable but that shouldn't shape what Supermemory knows about a user. Full explanation: [SuperRAG → Ingesting as pure SuperRAG](/concepts/super-rag#ingesting-as-pure-superrag-tasktype-superrag).
---
## Filtered writes
By default, when you add content, Supermemory uses **all** existing memories in the namespace as context for generating new memories. With **filtered writes**, you can scope this context to only memories from documents matching specific metadata.
This is useful when you have many documents in a namespace but want new memories to build on top of a specific subset — for example, only memories from a particular source, category, or user.
<Note>
The metadata itself is still written to the document, but the memories will only be built on top of what's already there matching the filter.
</Note>
<Tabs>
<Tab title="TypeScript">
```typescript
await supermemory.add("user_123", {
content: "New research findings on transformer architectures...",
metadata: { category: "ml", source: "arxiv" },
group: { category: "ml" },
});
```
</Tab>
<Tab title="Python">
```python
client.add(
"user_123",
content="New research findings on transformer architectures...",
metadata={"category": "ml", "source": "arxiv"},
group={"category": "ml"},
)
```
</Tab>
<Tab title="cURL">
```bash
curl -X POST "https://api.supermemory.ai/ns/user_123/document" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "New research findings on transformer architectures...",
"metadata": {"category": "ml", "source": "arxiv"},
"group": {"category": "ml"}
}'
```
</Tab>
</Tabs>
### How it works
When `group` is provided:
- **Profile memories** (static context) are filtered to only those from documents matching the metadata
- **Similar memories** used as context during ingestion are filtered the same way
- The new document's own metadata is written normally — the filter only affects which **existing** memories are used as context
### `group` parameter
| Key | Type | Description |
|-----|------|-------------|
| `group` | `Record<string, string \| number \| boolean \| string[]>` | Key-value pairs to filter existing memories by their source document metadata |
- **Scalar values** (string, number, boolean) match exactly
- **Array values** match if **any** value in the array matches (OR logic)
- **Multiple keys** are combined with AND logic
```typescript
// Match documents where category is "ml" AND source is either "arxiv" or "pubmed"
await supermemory.add("user_123", {
content: "...",
group: {
category: "ml",
source: ["arxiv", "pubmed"],
},
});
```
---
## Processing pipeline
When you add content, Supermemory:
1. **Validates** your request
2. **Stores** the document and queues for processing
3. **Extracts** content (OCR, transcription, web scraping)
4. **Chunks** into searchable memories
5. **Embeds** for vector search
6. **Indexes** for retrieval
Track progress with `GET /ns/{namespace}/document/{id}`:
```typescript
const doc = await supermemory.documents.get("user_123", "abc123");
console.log(doc.system.status); // "queued" | "processing" | "done"
```
<AccordionGroup>
<Accordion title="Batch upload">
Process multiple documents with rate limiting:
```typescript
async function batchUpload(documents: Array<{id: string, content: string}>) {
const results = [];
for (const doc of documents) {
try {
const result = await supermemory.add("batch_import", {
content: doc.content,
id: doc.id,
});
results.push({ id: doc.id, success: true, docId: result.id });
} catch (error) {
results.push({ id: doc.id, success: false, error });
}
// Rate limit: 1 second between requests
await new Promise(r => setTimeout(r, 1000));
}
return results;
}
```
**Tips:**
- Batch size: 3-5 documents at once
- Delay: 1-2 seconds between requests
- Use `id` to track and deduplicate
- For large backfills use `documents.batchAdd` instead. See [Backfill historical data](/ingestion/batch-ingest-historical-data)
</Accordion>
<Accordion title="Error handling">
| Status | Error | Cause |
|--------|-------|-------|
| 400 | Bad request | Missing required fields, invalid parameters |
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | Insufficient permissions |
| 429 | Rate limited | Too many requests or quota exceeded |
| 500 | Internal error | Processing failure |
```typescript
try {
await supermemory.add("user_123", { content: "..." });
} catch (error) {
// Back off on 429, fix the request on 400, retry later on 5xx
console.error("add failed:", error);
}
```
</Accordion>
<Accordion title="Delete Content">
**Delete by IDs (one or many, Supermemory or your own ids):**
```typescript
const { count, errors } = await supermemory.documents.delete("user_123", {
ids: ["doc_1", "doc_2", "doc_3"],
});
```
**Delete everything in a namespace:**
```typescript
// Delete all content for a user
await supermemory.namespaces.delete("user_123");
```
Deletes are permanent — no recovery.
</Accordion>
</AccordionGroup>
---
## Next steps
- [How to backfill historical data](/ingestion/batch-ingest-historical-data) — Import dated content with the batch API
- [Search Memories](/recall/search) — Query your content
- [User Profiles](/recall/user-profiles) — Get user context
- [Organizing & Filtering](/concepts/filtering) — Namespaces and metadata