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

# Local integrations

> Run provider-dependent web features during local development.

## Stripe webhooks

Run the app locally, then forward Stripe events:

```bash theme={null}
stripe listen --forward-to https://<your-selected-dev-deployment>.convex.site/stripe/webhook
```

Use matching Stripe test secrets for that explicitly selected personal development Convex backend. Do not forward to customer production; each isolated PR preview has its own test endpoint. The former Next.js webhook route was removed.

## Redis rate limiter QA

Redis client 6 uses RESP3 and requires Node.js 20 or newer. Use a disposable
local Redis instance for the opt-in TCP tests; never point them at customer
storage. Set `OVERLAY_REDIS_URL` explicitly and run
`NODE_OPTIONS=--require=./scripts/ci/register-server-only.cjs npx tsx --test src/server/shared/providers/redis-rate-limiter.test.ts`.
The live cases verify shared limits, concurrent requests and expiry; the same
file retains ordinary unit tests for fail-closed behavior without Redis.

## Auth

WorkOS sign-in flows require the local callback URL to match the WorkOS application settings. Keep local, Preview, and Production WorkOS credentials separate.

For OIDC deployments, including Keycloak-compatible realm issuers, verify browser callback wiring and token claims before production use.

Default web sign-in/sign-up and server SSO callbacks use the shared authenticated home (`/app/work`) when no return destination is supplied. Explicit same-origin paths, including `/account`, and supported desktop handoff redirects retain their existing validation and routing.

Protected-route sign-in redirects preserve the full path and query for both missing and invalid sessions, including Better Auth sign-in. In particular, `/account?desktop_code_challenge=...` must retain its PKCE challenge through sign-in and the account-settings alias; do not reduce the return destination to a pathname. Protected APIs still return 401 JSON rather than browser redirects.

## PR preview authentication

Migration previews use `https://pr-<number>.preview.getoverlay.io` with the
registered WorkOS sandbox wildcard callback. They do not require the paid
Vercel preview suffix. `POST /api/auth/preview-login` accepts the
`x-overlay-preview-secret` header only when both deployment markers say preview,
the canonical origin is valid, and the WorkOS client is Overlay's sandbox.
The server authenticates its configured QA email/password, checks the returned
user ID against the seeded identity, and creates the normal encrypted session.
It never returns provider tokens. Missing or incorrect configuration returns
404 before provider access; authenticated requests are rate limited.

Keep `PREVIEW_LOGIN_SECRET`, `PREVIEW_LOGIN_PASSWORD`, and the sandbox API key
in the web app's Preview scope. Convex receives only the seed user ID/email and
the matching internal secrets. The existing browser Convex-token endpoint issues
the short-lived subscription token after this login.

## Storage

R2 and S3-compatible storage flows use server-mediated upload and download routes. Test:

* Presign URL creation.
* Upload completion.
* Owner-scoped content access.
* File deletion.

## Observability

PostHog and Sentry are optional locally. Use separate projects or DSNs per environment. Do not send local secrets, access tokens, or customer data in logs.

## Composio

Composio catalog and connection setup require `COMPOSIO_API_KEY` on the Next.js server. Hosted deployments resolve WorkOS Vault first and fall back to the server environment. Keep the Vault object and deployment variable aligned when rotating the key.

Verify configuration through `GET /api/v1/integrations?action=health`. Catalog requests fail with an actionable provider/configuration error when the key is missing, rejected, or the upstream catalog is unavailable; an empty catalog is reserved for a successful response with no matches.

Connector visibility is workspace-scoped through `workspaceConnectors`. On the first Personal-workspace read after upgrading, active Composio accounts with no mapping in any workspace are assigned to Personal. Existing workspace mappings are never moved or duplicated.

## MCP tools

The MCP OAuth adapter preserves the SDK's authorization-server `issuer` binding
on both client information and tokens, inside the existing encrypted JSON
credential fields. Credentials loaded without an issuer are withheld from the
SDK and require reconnecting; do not infer their issuer from a new discovery
response or silently stamp existing secrets. The SDK refuses to send bound
credentials to a different issuer. This upgrade needs no new Convex schema
field.

AI SDK `toolsContext` is keyed by executable tool name. `call_mcp_tool` receives
its user, conversation, turn, and model attribution under the
`call_mcp_tool` key; a flat context object fails validation before the MCP
network call and leaves the transcript looking stuck. MCP calls have a
30-second default timeout and record a terminal execution row for success or
failure.

## Slack import via Composio

Slack import uses Composio's `SLACKBOT` toolkit with **direct tool execution** — not the LLM session-based flow used by agent tools. This is a deterministic, paginated backfill that runs as a server-side background job.

### Architecture

```
Workspace Settings → Import tab
  → Connect Slack (Composio OAuth, providerKey=slackbot)
  → Chats picker (SLACKBOT_LIST_ALL_CHANNELS)
  → Create import job (Convex slackImportJobs)
  → Backfill worker (server-side, not LLM):
      1. Fetch users (SLACKBOT_LIST_ALL_USERS)
      2. Per channel: create Overlay conversation
      3. Paginate history (SLACKBOT_FETCH_CONVERSATION_HISTORY)
      4. Fetch thread replies (SLACKBOT_FETCH_MESSAGE_THREAD_FROM_A_CONVERSATION)
      5. Download files (SLACKBOT_DOWNLOAD_FILE)
      6. Normalize → insert as conversationMessages
      7. Dedup via slackImportMappings
  → Progress via polling GET /api/v1/imports/slack?action=job
  → Coverage report on completion
```

### Key files

| Layer | File | Purpose |
| - | - | - |
| Convex schema | `convex/schema.ts` | `slackImportJobs`, `slackImportMappings` tables |
| Convex functions | `convex/imports/slackJobs.ts` | Job CRUD, live subscriptions, worker queries |
| Convex functions | `convex/imports/slackMappings.ts` | Source→Overlay ID mapping, dedup, resume |
| Server adapter | `src/server/imports/slack/composioClient.ts` | REST client for Composio direct tool execution |
| Server adapter | `src/server/imports/slack/normalizer.ts` | Slack → Overlay format transformation |
| Server adapter | `src/server/imports/slack/backfillWorker.ts` | Deterministic import loop |
| BFF route | `src/server/app-api/v1/imports/slack/route.ts` | GET (channels/jobs), POST (start/cancel) |
| BFF route | `src/app/api/v1/imports/slack/route.ts` | Next.js route handler |
| UI | `src/features/workspaces/components/SlackImportPanel.tsx` | 5-step panel (connect → people → chats → progress → done) |

### Direct tool execution vs LLM sessions

Agent tools use `createBrowserUnifiedTools()` which creates a Composio session per user and lets the LLM choose tool calls. The Slack importer does **not** use sessions. Instead it calls Composio's REST API directly:

```
POST https://backend.composio.dev/api/v3.1/tools/execute/{tool_slug}
  x-api-key: COMPOSIO_API_KEY
  body: { connected_account_id, arguments }
```

This gives deterministic pagination, retries, checkpointing, and predictable costs. The response wraps Slack's API response in a `data` field (sometimes as a JSON string that must be parsed).

### Composio Slackbot auth config

The `SLACKBOT` toolkit requires a Composio-managed auth config before OAuth can work. If one doesn't exist, the connect flow will fail. Auth configs are created via:

```
POST /api/v3.1/auth_configs
  body: { toolkit: { slug: "slackbot" }, ... }
```

The auth config is project-scoped in Composio. Once created, the standard `connectResponse({ providerKey: 'slackbot' })` flow works from the UI.

### Rate limit considerations

* The backfill worker adds small delays between thread fetches (200ms) to avoid rate limits.
* Composio may return rate limit errors from Slack's API. The worker logs these but continues with other channels.
* Channel listing is cached per import job — the worker lists channels once at the start.
* For large workspaces, the import may take several minutes. Progress is reported via Convex job status updates after each channel.

### Slack access limitations

A Slack bot/user token only sees conversations the authenticated account can access:

* **Public channels:** broadly accessible
* **Private channels:** only if the bot/user is a member
* **DMs:** only the authenticated user's DMs
* **MPIMs:** only if the user is a participant

The coverage report distinguishes public/private/DM/MPIM counts so users understand what was actually imported vs what exists in their Slack workspace. For full workspace export, Slack's admin ZIP export or Enterprise Discovery API would be needed (not implemented yet).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.