Connector content via the public REST API

Search synced connector content + list configured connectors programmatically via the kodori-sdk or direct REST calls. Required scope: search:read.

Updated 2026-04-30

Two endpoints expose connector content to integrations without going through `/api/mcp`:

## POST /api/v1/search/external

Hybrid search (FTS + pgvector + RRF) across content synced from every authorized connector. Same shape as `searchExternalContent` on the MCP catalog.

Request body: ```json { "query": "indemnity language", "kind": "slack", "limit": 20 } ```

`kind` is optional — omit for cross-vendor search across slack / gmail / outlook / sharepoint / onedrive / google-drive. `limit` defaults to 20, max 100.

Response: ```json { "messages": [ { "id": "...", "vendorKind": "slack", "channelName": "#legal", "authorName": "Sam", "snippet": "...", "url": "https://app.slack.com/client/T.../C.../p...", "sentAt": "2026-04-29T...", "score": 0.0327, "source": "both" } ], "documents": [ { "id": "...", "vendorKind": "sharepoint", "name": "Q3-board-deck.docx", "snippet": "...", "url": "https://contoso.sharepoint.com/...", "modifiedAt": "2026-04-28T...", "score": 0.0298, "source": "keyword" } ] } ```

## GET /api/v1/connectors

Read-only listing of every external connector configured for the tenant. Includes status, kind, display name, lifecycle timestamps, and aggregate content counts (messages / documents / extracted / failed).

Response: ```json { "connectors": [ { "id": "...", "kind": "slack", "displayName": "Acme Workspace", "status": "connected", "createdAt": "2026-04-30T...", "lastSyncCompletedAt": "2026-04-30T...", "lastSyncError": null, "syncIntervalMinutes": null, "revokedAt": null, "content": { "messageCount": 1247, "documentCount": 89, "extractedCount": 86, "extractionFailedCount": 3 } } ] } ```

Tokens, scope strings, and config payloads are NOT returned — those live behind the admin UI at `/integrations`.

## Using the SDK

The `@kumokodo/kodori-sdk` (0.2.0+) wraps both endpoints with typed methods:

```typescript import { KodoriClient } from '@kumokodo/kodori-sdk';

const kodori = new KodoriClient({ apiKey: process.env.KODORI_API_KEY! });

const hits = await kodori.externalSearch.run({ query: 'indemnity language', kind: 'slack', limit: 20, });

const list = await kodori.connectors.list(); ```

Required scope on the API key: `search:read` (the baseline scope — every key has it). No new onboarding step.