docs(connectors): align connector docs with the v5 API (#1812)

Fixes connector docs.

- **`authorization.url` examples.** They now show the URL the API actually returns (`/v3/connections/auth/redirect?state=…`), not provider URLs.
- **Broken examples:**
  - TS `connectors.create` examples were missing commas.
  - Python dicts now use the SDK's snake_case keys.
  - `connector.createdAt` → `connector.system.createdAt`.
  - The list default `limit` is 10.
- **Pending connectors.** They are visible through get (`pending_authorization`), just not in list.
- **Gmail:**
  - It needs the Max plan.
  - Nothing syncs until labels are picked.
  - The watch covers the selected labels, not just INBOX.
  - `from` filters use `contains`.
- **Smaller fixes:**
  - The OAuth redirect-URI troubleshooting.
  - Notion property metadata keys.
  - Picker error codes.

Checked against the current API and the published SDKs (TS 5.0.1, Python 5.0.0). Legacy v3/v4 docs are unchanged apart from factual fixes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
sohamd22 2026-10-15 18:52:41 +00:00
parent 2197c04ac1
commit 2a546ff654
12 changed files with 112 additions and 102 deletions

View file

@ -24,7 +24,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**.
const connector = await supermemory.connectors.create("user-123", {
provider: "github",
redirectUrl: "https://yourapp.com/auth/github/callback"
redirectUrl: "https://yourapp.com/auth/github/callback",
documentLimit: 5000,
})
@ -44,8 +44,8 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**.
"user-123",
request={
"provider": "github",
"redirectUrl": "https://yourapp.com/auth/github/callback",
"documentLimit": 5000,
"redirect_url": "https://yourapp.com/auth/github/callback",
"document_limit": 5000,
},
)
@ -68,7 +68,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**.
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://github.com/login/oauth/authorize?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -85,7 +85,7 @@ The GitHub connector requires a **Scale Plan** or **Enterprise Plan**.
### 2. Handle OAuth callback
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, GitHub redirects to your `redirectUrl`. A pending OAuth connector is not visible in list or get until the user finishes authorization. Once it is visible, the user can select which repositories to sync.
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Supermemory sends them to a hosted repository picker; once they choose repositories, they return to your `redirectUrl`. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
### 3. Select Repositories
@ -224,7 +224,9 @@ Webhooks are secured using HMAC-SHA256 signature validation with constant-time c
print(f"Webhooks: {connector.capabilities.webhooks}")
print(f"Last synced: {connector.system.last_successful_sync_at}")
print(f"Last sync: {connector.latest_run.system.status} {connector.latest_run.error}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
if connector.latest_run and connector.latest_run.error:
print(connector.latest_run.error)
repos = (connector.selection or {}).get("repos") or []
print(f"Repositories: {[r.name for r in repos]}")
print(f"Recent runs: {connector.syncs}")
@ -255,7 +257,7 @@ Webhooks are secured using HMAC-SHA256 signature validation with constant-time c
console.log(`Provider: ${connector.provider}`)
console.log(`ID: ${connector.id}`)
console.log(`Account: ${connector.account}`)
console.log(`Created: ${connector.createdAt}`)
console.log(`Created: ${connector.system.createdAt}`)
console.log(`Document limit: ${connector.documentLimit}`)
console.log(`Repositories: ${connector.selection?.repos?.length ?? 0}`)
console.log("---")
@ -271,7 +273,7 @@ Webhooks are secured using HMAC-SHA256 signature validation with constant-time c
print(f"Provider: {connector.provider}")
print(f"ID: {connector.id}")
print(f"Account: {connector.account}")
print(f"Created: {connector.created_at}")
print(f"Created: {connector.system.created_at}")
print(f"Document limit: {connector.document_limit}")
repos = (connector.selection or {}).get("repos") or []
print(f"Repositories: {len(repos)}")

View file

@ -24,7 +24,7 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg
const connector = await supermemory.connectors.create("user-123", {
provider: "gmail",
redirectUrl: "https://yourapp.com/auth/gmail/callback"
redirectUrl: "https://yourapp.com/auth/gmail/callback",
documentLimit: 5000,
})
@ -44,8 +44,8 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg
"user-123",
request={
"provider": "gmail",
"redirectUrl": "https://yourapp.com/auth/gmail/callback",
"documentLimit": 5000,
"redirect_url": "https://yourapp.com/auth/gmail/callback",
"document_limit": 5000,
},
)
@ -68,7 +68,7 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://accounts.google.com/o/oauth2/v2/auth?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -78,7 +78,9 @@ Connect Gmail to automatically sync email threads into your supermemory knowledg
### 2. Handle OAuth callback
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Google redirects to your `redirectUrl` and the initial sync begins. A pending OAuth connector is not visible in list or get until the user finishes authorization.
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Supermemory sends them to a hosted label picker; once they choose labels, they return to your `redirectUrl` and the initial sync begins. Nothing syncs until at least one label is selected. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
To change the labels later, read the connector with `include: "picker"` and send the user to `picker.url`, or set label ids directly with `connectors.update(namespace, id, { selection: { labels: ["INBOX"] } })`. See [Managing Connector Selection](/connectors/managing-resources).
### 3. Check Connector Status
@ -106,7 +108,7 @@ Send the user to `authorization.url` before `authorization.expiresAt`. After the
connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=["syncs"])
print(f"Connected email: {connector.account}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
print(f"Threads synced: {connector.document_count}")
# List synced email threads in the namespace
@ -155,8 +157,8 @@ Each synced thread includes searchable metadata:
| `type` | Always `gmail_thread` |
| `subject` | Email subject line |
| `threadId` | Gmail thread ID |
| `from` | Sender email address |
| `to` | Recipient email addresses |
| `from` | Sender, as the raw `From` header (for example `Team <team@company.com>`) |
| `to` | Recipient addresses, comma-separated |
| `date` | Date of first message |
| `messageCount` | Number of messages in thread |
| `attachmentCount` | Number of attachments (if any) |
@ -171,7 +173,7 @@ const results = await supermemory.search("user-123", {
operator: "and",
operands: [
{ field: "type", operator: "eq", value: "gmail_thread" },
{ field: "from", operator: "eq", value: "team@company.com" },
{ field: "from", operator: "contains", value: "team@company.com" },
],
},
searchMode: "chunks",
@ -192,7 +194,7 @@ const results = await supermemory.search("user-123", {
console.log(`Provider: ${connector.provider}`)
console.log(`ID: ${connector.id}`)
console.log(`Account: ${connector.account}`)
console.log(`Created: ${connector.createdAt}`)
console.log(`Created: ${connector.system.createdAt}`)
console.log(`Document limit: ${connector.documentLimit}`)
console.log("---")
})
@ -207,7 +209,7 @@ const results = await supermemory.search("user-123", {
print(f"Provider: {connector.provider}")
print(f"ID: {connector.id}")
print(f"Account: {connector.account}")
print(f"Created: {connector.created_at}")
print(f"Created: {connector.system.created_at}")
print(f"Document limit: {connector.document_limit}")
print("---")
```
@ -308,13 +310,13 @@ Gmail connector supports multiple sync methods:
### How real-time sync works
1. When a connector is created, supermemory registers a Gmail API "watch" subscription
1. After labels are selected, supermemory registers a Gmail API "watch" subscription when Pub/Sub is configured
2. Gmail sends notifications to a Google Cloud Pub/Sub topic when emails change
3. supermemory receives these notifications and fetches updated threads
4. Watch subscriptions expire after 7 days and are automatically renewed
<Note>
Real-time sync monitors the **INBOX** label. Emails in other labels are synced via scheduled/manual sync.
Real-time sync monitors the selected labels, including labels outside **INBOX**. If multiple connectors use the same mailbox, its watch covers their combined label selections.
</Note>
## Permissions & scopes

View file

@ -32,7 +32,7 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled
const connector = await supermemory.connectors.create("user-123", {
provider: "google-drive",
redirectUrl: "https://yourapp.com/auth/google-drive/callback"
redirectUrl: "https://yourapp.com/auth/google-drive/callback",
documentLimit: 3000,
config: { syncScope: "selected" },
})
@ -53,9 +53,9 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled
"user-123",
request={
"provider": "google-drive",
"redirectUrl": "https://yourapp.com/auth/google-drive/callback",
"documentLimit": 3000,
"config": {"syncScope": "selected"},
"redirect_url": "https://yourapp.com/auth/google-drive/callback",
"document_limit": 3000,
"config": {"sync_scope": "selected"},
},
)
@ -79,7 +79,7 @@ If you use scoped sync and the user has not finished the picker yet, **scheduled
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://accounts.google.com/o/oauth2/v2/auth?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -93,7 +93,7 @@ For **whole Drive** sync, send `"config": { "syncScope": "full" }` on the same `
### 2. Handle OAuth callback
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Google redirects through Supermemory to finish the connector. A pending OAuth connector is not visible in list or get until the user finishes authorization.
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Google redirects through Supermemory to finish the connector. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
With **scoped** sync (`syncScope` omitted or `"selected"`), the user is sent to Supermemory’s **hosted file and folder picker**; they must complete that step before syncs run. With **`syncScope: "full"`**, Supermemory redirects to your `redirectUrl` **without** the picker.
@ -173,7 +173,7 @@ If you already know the Drive file and folder ids, set them directly. A new sele
print(f"Account: {connector.account}")
print(f"Selection: {connector.selection}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
# List synced documents in the namespace
documents = client.list("user-123", "documents").documents
@ -205,6 +205,8 @@ Based on the API type definitions, Google Drive documents are identified with th
- `google_slide` - Google Slides
- `google_sheet` - Google Sheets
PDF and Markdown files stored in Drive are synced too.
<Note>
Drive documents are converted to markdown before ingestion. This conversion is lossy — some formatting may not be preserved.
</Note>
@ -223,7 +225,7 @@ Drive documents are converted to markdown before ingestion. This conversion is l
console.log(`Provider: ${connector.provider}`)
console.log(`ID: ${connector.id}`)
console.log(`Account: ${connector.account}`)
console.log(`Created: ${connector.createdAt}`)
console.log(`Created: ${connector.system.createdAt}`)
console.log(`Document limit: ${connector.documentLimit}`)
console.log("---")
})
@ -238,7 +240,7 @@ Drive documents are converted to markdown before ingestion. This conversion is l
print(f"Provider: {connector.provider}")
print(f"ID: {connector.id}")
print(f"Account: {connector.account}")
print(f"Created: {connector.created_at}")
print(f"Created: {connector.system.created_at}")
print(f"Document limit: {connector.document_limit}")
print("---")
```
@ -263,7 +265,7 @@ Drive documents are converted to markdown before ingestion. This conversion is l
# "system": { "status": "active", "createdAt": "2024-01-15T10:30:00.000Z", "lastSuccessfulSyncAt": "..." }
# }
# ],
# "pagination": { "currentPage": 1, "limit": 50, "totalItems": 1, "totalPages": 1 }
# "pagination": { "currentPage": 1, "limit": 10, "totalItems": 1, "totalPages": 1 }
# }
```
</Tab>

View file

@ -61,9 +61,9 @@ The console limits connector setup to 500 documents. Use the API setup below for
request={
"provider": "granola",
"config": {
"apiKey": os.environ["GRANOLA_API_KEY"],
"api_key": os.environ["GRANOLA_API_KEY"],
},
"documentLimit": 1000,
"document_limit": 1000,
},
)

View file

@ -83,7 +83,7 @@ curl "https://api.supermemory.ai/ns/user-123/connectors/{connectorId}?include=pi
```
<Note>
The picker link works once, in any browser. `picker` is `null` for connectors that sync everything.
The picker link works once, in any browser. `picker` is `null` for providers that do not support selection. A Google Drive connector with full-drive sync can still open the picker; saving a selection switches it to scoped sync. Because the link changes what syncs, `include=picker` needs an admin key with write access to the namespace; otherwise the request returns `403`.
</Note>
## Set the Selection Directly
@ -121,7 +121,7 @@ connector = client.connectors.update(
)
print(f"Selection: {connector.selection}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
```
```bash cURL
@ -173,9 +173,11 @@ The updated connector object, including the saved `selection` as `{ id, name }`
### Error Responses
- `400`: Connector does not support selection
- `400`: Connector does not support selection, the selection is empty or has unknown ids, or the connector needs to be reconnected
- `401`: Unauthorized
- `403`: The key lacks admin role or write access to the connector's namespaces
- `404`: Connector not found
- `409`: Connector is still waiting for the user to finish authorizing
<Note>
**Automatic Sync:** After a selection is saved, a sync starts for the connector. You don't need to call `connectors.sync` afterwards.
@ -193,10 +195,11 @@ const created = await supermemory.connectors.create("user-123", {
redirectUrl: "https://yourapp.com/callback"
})
// 2. Send the user to GitHub; the connector becomes visible once they authorize
// 2. Send the user to GitHub. After they authorize, Supermemory shows the hosted
// repository picker, then returns them to redirectUrl
if (created.authorization) window.location.href = created.authorization.url
// 3. After the callback, open the hosted picker so the user chooses repositories
// 3. To change repositories later, open the hosted picker again
const connector = await supermemory.connectors.get("user-123", created.id, {
include: "picker",
returnUrl: "https://yourapp.com/settings/integrations"
@ -215,14 +218,15 @@ created = client.connectors.create(
"user-123",
request={
"provider": "github",
"redirectUrl": "https://yourapp.com/callback",
"redirect_url": "https://yourapp.com/callback",
},
)
# 2. Send the user to GitHub; the connector becomes visible once they authorize
# 2. Send the user to GitHub. After they authorize, Supermemory shows the hosted
# repository picker, then returns them to redirect_url
print(f"Redirect to: {created.authorization.url}")
# 3. After the callback, open the hosted picker so the user chooses repositories
# 3. To change repositories later, open the hosted picker again
connector = client.connectors.get(
"user-123",
created.id,
@ -247,9 +251,9 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
-H "Content-Type: application/json" \
-d '{"provider": "github", "redirectUrl": "https://yourapp.com/callback"}'
# 2. ... (user authorizes at authorization.url) ...
# 2. ... (user authorizes at authorization.url and picks repositories in the hosted picker) ...
# 3. Get a one-time hosted picker URL
# 3. To change repositories later, get a one-time hosted picker URL
curl "https://api.supermemory.ai/ns/user-123/connectors/{connectorId}?include=picker" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"

View file

@ -19,7 +19,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl
const connector = await supermemory.connectors.create("user-123", {
provider: "notion",
redirectUrl: "https://yourapp.com/auth/notion/callback"
redirectUrl: "https://yourapp.com/auth/notion/callback",
documentLimit: 2000,
})
@ -38,8 +38,8 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl
"user-123",
request={
"provider": "notion",
"redirectUrl": "https://yourapp.com/auth/notion/callback",
"documentLimit": 2000,
"redirect_url": "https://yourapp.com/auth/notion/callback",
"document_limit": 2000,
},
)
@ -61,7 +61,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://api.notion.com/v1/oauth/authorize?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -71,7 +71,7 @@ Connect Notion workspaces to automatically sync pages, databases, and content bl
### 2. Handle OAuth flow
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants workspace access, Notion redirects to your `redirectUrl` and the first sync starts. A pending OAuth connector is not visible in list or get until the user finishes authorization.
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants workspace access, Notion redirects to your `redirectUrl` and the first sync starts. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
### 3. Monitor sync progress
@ -97,7 +97,7 @@ Send the user to `authorization.url` before `authorization.expiresAt`. After the
connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=["syncs"])
print(f"Connected workspace: {connector.account}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
print(f"Documents synced: {connector.document_count}")
# List synced pages and databases
@ -268,15 +268,15 @@ Notion connector respects workspace permissions:
### Database properties
Notion database properties are mapped to metadata:
Notion database properties are mapped to metadata keys named `notion_prop_<property name>`, lowercased with spaces replaced by underscores (a `Status` property becomes `notion_prop_status`). The page title is stored as `title`, and every page has `type: "notion_doc"`.
```typescript
// List documents in the namespace (there is no per-connector document list in v5)
const { documents } = await supermemory.list("user-123", "documents")
// Find database entries
// Find database entries by a property value
const projectEntries = documents.filter(doc =>
doc.metadata?.database === "Projects"
doc.metadata?.notion_prop_status === "In Progress"
)
// Database properties become searchable metadata
@ -285,8 +285,8 @@ const projectWithStatus = await supermemory.search("user-123", {
filter: {
operator: "and",
operands: [
{ field: "status", operator: "eq", value: "In Progress" },
{ field: "priority", operator: "eq", value: "High" },
{ field: "notion_prop_status", operator: "eq", value: "In Progress" },
{ field: "notion_prop_priority", operator: "eq", value: "High" },
],
},
searchMode: "chunks",

View file

@ -21,13 +21,13 @@ const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
const connector = await supermemory.connectors.create("user-123", {
provider: "onedrive",
redirectUrl: "https://yourapp.com/auth/onedrive/callback"
redirectUrl: "https://yourapp.com/auth/onedrive/callback",
documentLimit: 1500,
})
// Send the user to Microsoft to authorize
if (connector.authorization) window.location.href = connector.authorization.url
// Output: Redirects to https://login.microsoftonline.com/oauth2/authorize?...
// Output: Redirects to https://api.supermemory.ai/v3/connections/auth/redirect?state=...
```
```python Python
@ -40,14 +40,14 @@ connector = client.connectors.create(
"user-123",
request={
"provider": "onedrive",
"redirectUrl": "https://yourapp.com/auth/onedrive/callback",
"documentLimit": 1500,
"redirect_url": "https://yourapp.com/auth/onedrive/callback",
"document_limit": 1500,
},
)
# Send the user to Microsoft to authorize
print(f"Redirect to: {connector.authorization.url}")
# Output: Redirect to: https://login.microsoftonline.com/oauth2/authorize?...
# Output: Redirect to: https://api.supermemory.ai/v3/connections/auth/redirect?state=...
```
```bash cURL
@ -63,7 +63,7 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://login.microsoftonline.com/oauth2/authorize?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -73,7 +73,7 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
### 2. Handle Microsoft OAuth
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Microsoft redirects to your `redirectUrl` and the initial sync begins. A pending OAuth connector is not visible in list or get until the user finishes authorization.
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Microsoft redirects to your `redirectUrl` and the initial sync begins. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
### 3. Monitor sync status
@ -96,7 +96,7 @@ Send the user to `authorization.url` before `authorization.expiresAt`. After the
connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=["syncs"])
print(f"Account: {connector.account}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
print(f"Documents synced: {connector.document_count}")
# List synced Office documents in the namespace

View file

@ -7,7 +7,7 @@ icon: "/icons/hugeicons/layers-01.svg"
Connect external platforms to automatically sync documents into supermemory. Supported connectors include Google Drive, Gmail, Notion, OneDrive, GitHub, Granola and Web Crawler with real-time synchronization and intelligent content processing.
Every connector belongs to one namespace. The namespace goes in the URL (`/ns/{namespace}/connectors`) and is a top-level `namespace` key in every SDK call.
New v5 connectors belong to one namespace. The namespace goes in the URL (`/ns/{namespace}/connectors`) and is the first argument of namespace-scoped SDK calls. Organization-wide listing uses `connectors.listAll()` in TypeScript or `connectors.list_all()` in Python without a namespace argument. Legacy connectors can span multiple namespaces or have no namespace.
## Supported connectors
@ -69,7 +69,7 @@ const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
const connector = await supermemory.connectors.create("user-123", {
provider: "notion",
redirectUrl: "https://yourapp.com/callback"
redirectUrl: "https://yourapp.com/callback",
documentLimit: 5000,
})
@ -77,7 +77,7 @@ const connector = await supermemory.connectors.create("user-123", {
console.log("Connector:", connector.id)
console.log("Auth URL:", connector.authorization?.url)
console.log("Expires at:", connector.authorization?.expiresAt)
// Output: Auth URL: https://api.notion.com/v1/oauth/authorize?...
// Output: Auth URL: https://api.supermemory.ai/v3/connections/auth/redirect?state=...
```
```python Python
@ -90,8 +90,8 @@ connector = client.connectors.create(
"user-123",
request={
"provider": "notion",
"redirectUrl": "https://yourapp.com/callback",
"documentLimit": 5000,
"redirect_url": "https://yourapp.com/callback",
"document_limit": 5000,
},
)
@ -99,7 +99,7 @@ connector = client.connectors.create(
print(f"Connector: {connector.id}")
print(f"Auth URL: {connector.authorization.url}")
print(f"Expires at: {connector.authorization.expires_at}")
# Output: Auth URL: https://api.notion.com/v1/oauth/authorize?...
# Output: Auth URL: https://api.supermemory.ai/v3/connections/auth/redirect?state=...
```
```bash cURL
@ -115,7 +115,7 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
# Response: {
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "authorization": {
# "url": "https://api.notion.com/v1/oauth/authorize?...",
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
# "expiresAt": "2024-01-15T11:30:00.000Z"
# }
# }
@ -125,7 +125,7 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
### 2. Handle OAuth callback
Send the user to `authorization.url` before `authorization.expiresAt`. When the user authorizes, the provider returns them to your `redirectUrl` and the first sync starts. A pending OAuth connector is not visible in list or get until the user finishes authorization.
Send the user to `authorization.url` before `authorization.expiresAt`. When the user authorizes, the provider returns them to your `redirectUrl` and the first sync starts. GitHub, Gmail and Google Drive (with the default `syncScope: "selected"`) first send the user through Supermemory's hosted picker to choose what to sync. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
Config providers (Web Crawler, S3, Granola) return `authorization: null` and start syncing immediately.
@ -167,7 +167,9 @@ connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=
print(f"Provider: {connector.provider}")
print(f"Account: {connector.account}")
print(f"Last sync: {connector.latest_run.system.status} {connector.latest_run.error}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
if connector.latest_run and connector.latest_run.error:
print(connector.latest_run.error)
print(f"Last synced at: {connector.system.last_successful_sync_at}")
print(f"Documents: {connector.document_count}")
print(f"Recent runs: {connector.syncs}")
@ -210,9 +212,9 @@ curl -X POST "https://api.supermemory.ai/ns/user-123/list/documents" \
### Authentication flow
1. **Create Connector**: Call `POST /ns/{namespace}/connectors` with a `provider`. OAuth providers return an `authorization` link; config providers (Web Crawler, S3, Granola) take a `config` object and return `authUrl: null`
1. **Create Connector**: Call `POST /ns/{namespace}/connectors` with a `provider`. OAuth providers return an `authorization` link; config providers (Web Crawler, S3, Granola) take a `config` object and return `authorization: null`
2. **User Authorization**: Send the user to `authorization.url` when the provider requires it
3. **Automatic Setup**: Connector established, sync begins immediately
3. **Automatic Setup**: The connector is established. Save any required label, repository, or file selection before content sync can proceed; providers without a selection step start their initial sync after setup
4. **Continuous Sync**: Real-time updates via webhooks + scheduled sync every 4 hours (or scheduled recrawling for Web Crawler)
### Document processing pipeline
@ -301,7 +303,7 @@ curl "https://api.supermemory.ai/ns/org-123/connectors" \
# "system": { "status": "active", "createdAt": "2024-01-15T10:30:00.000Z", "lastSuccessfulSyncAt": "2024-01-15T10:45:00.000Z" }
# }
# ],
# "pagination": { "currentPage": 1, "limit": 50, "totalItems": 1, "totalPages": 1 }
# "pagination": { "currentPage": 1, "limit": 10, "totalItems": 1, "totalPages": 1 }
# }
# Connectors across every namespace in the organization

View file

@ -48,8 +48,8 @@ The S3 connector requires a **Scale Plan** or higher. You can also create S3 con
"config": {
"bucket": "my-documents-bucket",
"region": "us-east-1",
"accessKeyId": os.environ["AWS_ACCESS_KEY_ID"],
"secretAccessKey": os.environ["AWS_SECRET_ACCESS_KEY"],
"access_key_id": os.environ["AWS_ACCESS_KEY_ID"],
"secret_access_key": os.environ["AWS_SECRET_ACCESS_KEY"],
},
},
)
@ -270,7 +270,9 @@ Minimum required permissions:
## Error codes
| Code | Message | Solution |
Supermemory checks the credentials against the bucket before it creates the connector. If that check fails, `POST /ns/{namespace}/connectors` returns `400` with one of these messages. The code column is the status S3 returned.
| S3 status | Message | Solution |
|------|---------|----------|
| 401 | Authentication failed | Verify access key and secret |
| 403 | Access denied | Check IAM permissions and bucket policy |

View file

@ -72,7 +72,7 @@ curl "https://api.supermemory.ai/ns/user-123/connectors/PTzGiUYei7pgzg5buzZHgA?i
curl -X POST "https://api.supermemory.ai/ns/user-123/list/documents" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filter": {"field": "source", "operator": "eq", "value": "notion"}}'
-d '{"filter": {"field": "type", "operator": "eq", "value": "notion_doc"}}'
```
</CodeGroup>
@ -85,30 +85,26 @@ There is no per-connector document list in v5. `supermemory.list(namespace, "doc
### Connector Missing From List
**Problem:** `connectors.create` returned an `id`, but `connectors.list` and `connectors.get` do not show it
**Problem:** `connectors.create` returned an `id`, but `connectors.list` does not show it
**Solution:** A pending OAuth connector is not visible in list or get until the user finishes authorization. Send the user to `authorization.url` before `authorization.expiresAt`. If the link expired, create the connector again.
**Solution:** A pending OAuth connector is not returned by list until the user finishes authorization. `connectors.get` still returns it with `system.status: "pending_authorization"`. Send the user to `authorization.url` before `authorization.expiresAt`. If the link expired, create the connector again.
### OAuth callback fails
**Problem:** "Invalid redirect URI" error after user grants permissions
**Solution:** Ensure your redirect URL matches EXACTLY what's configured in your OAuth app:
**Solution:** The provider always redirects to Supermemory's callback, not to your `redirectUrl`. If you use a [custom OAuth application](/connectors/overview#custom-oauth-applications), its redirect URI must be exactly `https://api.supermemory.ai/v3/connections/auth/callback/{provider}`. Your `redirectUrl` is where Supermemory sends the user after it handles that callback, and must be an `http` or `https` URL:
```typescript
// correct - exact match with OAuth app settings
const connector = await supermemory.connectors.create("user-123", {
provider: "notion",
redirectUrl: "https://yourapp.com/auth/notion/callback"
})
// Wrong - URL doesn't match
// redirectUrl: "https://yourapp.com/callback"
```
**Prevention:**
- Use HTTPS for production URLs
- Copy the exact URL from your OAuth app settings
- Register `https://api.supermemory.ai/v3/connections/auth/callback/{provider}` in your custom OAuth app settings
- Test the flow in development first
### Documents not syncing
@ -159,7 +155,7 @@ if (next.authorization) window.location.href = next.authorization.url
```typescript
const connector = await supermemory.connectors.create("user-123", {
provider: "onedrive",
redirectUrl: "https://yourapp.com/callback"
redirectUrl: "https://yourapp.com/callback",
documentLimit: 500, // Start with fewer documents
})
@ -247,9 +243,9 @@ const next = await supermemory.connectors.create("user-123", {
})
```
**Scale Plan Required Error**
**Max Plan Required Error**
Gmail connector requires Scale Plan or Enterprise Plan. If you see access errors:
Gmail connector requires Max Plan or above. If you see access errors:
- Verify your organization has the required plan
- Contact support to upgrade your plan

View file

@ -48,16 +48,16 @@ The web crawler connector requires a **Scale Plan** or **Enterprise Plan**.
request={
"provider": "web-crawler",
"config": {
"startUrl": "https://docs.example.com",
"crawlDepth": 3,
"start_url": "https://docs.example.com",
"crawl_depth": 3,
},
"documentLimit": 5000,
"document_limit": 5000,
},
)
# Web crawler doesn't require OAuth; crawling starts immediately
print(f"Connector ID: {connector.id}")
# Note: connector.authorization.url is None for web-crawler
# Note: connector.authorization is None for web-crawler
```
</Tab>
<Tab title="cURL">
@ -120,7 +120,7 @@ Unlike OAuth connectors, the web crawler doesn't require user authorization. `au
connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=["syncs"])
print(f"Start URL: {(connector.config or {}).get('startUrl')}")
print(f"Last sync: {connector.latest_run.system.status}")
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
print(f"Pages synced: {connector.document_count}")
# List synced web pages in the namespace
@ -229,7 +229,7 @@ Start a crawl now. The call returns `409` while a sync for that connector is alr
webCrawlerConnectors.forEach(connector => {
console.log(`Start URL: ${connector.config?.startUrl}`)
console.log(`Connector ID: ${connector.id}`)
console.log(`Created: ${connector.createdAt}`)
console.log(`Created: ${connector.system.createdAt}`)
})
```
</Tab>
@ -241,7 +241,7 @@ Start a crawl now. The call returns `409` while a sync for that connector is alr
for connector in connectors:
print(f"Start URL: {(connector.config or {}).get('startUrl')}")
print(f"Connector ID: {connector.id}")
print(f"Created: {connector.created_at}")
print(f"Created: {connector.system.created_at}")
```
</Tab>
<Tab title="cURL">
@ -256,12 +256,12 @@ Start a crawl now. The call returns `409` while a sync for that connector is alr
# "id": "PTzGiUYei7pgzg5buzZHgA",
# "provider": "web-crawler",
# "namespace": "user-123",
# "createdAt": "2024-01-15T10:30:00.000Z",
# "documentLimit": 5000,
# "config": {"startUrl": "https://docs.example.com", "crawlDepth": 3}
# "config": {"startUrl": "https://docs.example.com", "crawlDepth": 3},
# "system": { "status": "active", "createdAt": "2024-01-15T10:30:00.000Z", "lastSuccessfulSyncAt": "..." }
# }
# ],
# "pagination": { "currentPage": 1, "limit": 50, "totalItems": 1, "totalPages": 1 }
# "pagination": { "currentPage": 1, "limit": 10, "totalItems": 1, "totalPages": 1 }
# }
```
</Tab>

View file

@ -13,7 +13,7 @@ icon: "/icons/hugeicons/book-open-01.svg"
| `PATCH /ns/{namespace}/connectors/{id}` | Change what it syncs: `selection` and `documentLimit` |
| `POST /ns/{namespace}/connectors/{id}/sync` | Trigger a sync now. Returns 409 while one is already running |
| `DELETE /ns/{namespace}/connectors/{id}` | Disconnect, optionally deleting the documents it imported |
| `GET /connectors` | List every connector in the organization, across namespaces |
| `GET /connectors` | List connectors across every namespace this key can read |
Providers: `notion`, `google-drive`, `onedrive`, `gmail`, `github` authenticate with OAuth. `web-crawler`, `s3`, and `granola` take their configuration in the create body and need no login.
@ -32,7 +32,7 @@ const { id, authorization } = await supermemory.connectors.create("user_123", {
// Config provider: starts syncing immediately, authorization is null
const crawler = await supermemory.connectors.create("user_123", {
provider: "web-crawler",
config: { startUrl: "https://docs.example.com" }
config: { startUrl: "https://docs.example.com" },
documentLimit: 200,
})
@ -48,7 +48,7 @@ curl -X POST "https://api.supermemory.ai/ns/user_123/connectors" \
</CodeGroup>
<Note>
A pending OAuth connector is not returned by list or get until the user completes authorization. The `authorization.url` expires after one hour (see `authorization.expiresAt`).
A pending OAuth connector is not returned by list until the user completes authorization. Get still returns it, with `system.status: "pending_authorization"`. The `authorization.url` expires after one hour (see `authorization.expiresAt`).
</Note>
See the [connector guides](/connectors/overview) for per-provider setup, selection rules, and troubleshooting.