---
title: Vercel Connect
description: Authenticate Slack, Discord, GitHub, Linear, Notion, and Telegram adapters with Vercel Connect — short-lived runtime tokens for outbound calls and OIDC-verified inbound webhooks where supported.
type: overview
related:
  - /docs/usage
  - /adapters/official/slack
  - /adapters/official/discord
  - /adapters/official/github
  - /adapters/official/linear
  - /adapters/official/notion
  - /adapters/official/telegram
---

# Vercel Connect



[Vercel Connect](https://vercel.com/docs/connect) lets your bot use a registered connector for adapter authentication instead of storing long-lived provider secrets. You register a connector once, link it to your project and environments, and your code requests scoped, short-lived tokens at runtime.

The `@vercel/connect/chat` subpath ships a helper per platform that you spread into the matching `create*Adapter` factory:

* `connectSlackAdapter`
* `connectDiscordAdapter`
* `connectGitHubAdapter`
* `connectLinearAdapter`
* `connectNotionAdapter`
* `connectTelegramAdapter`

Each helper wires outbound credentials; trigger-capable providers also wire
inbound traffic:

* **Outbound** (your bot calls the provider API) — a function-form token field that resolves a fresh, short-lived token per call via `getToken`.
* **Inbound** (the provider calls your bot) — trigger-capable helpers include a `webhookVerifier` that validates the Vercel OIDC token Connect attaches to [trigger-forwarded](https://vercel.com/docs/connect/concepts/triggers) webhooks, replacing the provider's native signature check.

<Callout type="info">
  Vercel Connect is in beta. Features and behavior, including available connectors and trigger forwarding, may change before general availability.
</Callout>

## Install

```bash
pnpm add @vercel/connect
```

`@vercel/connect` reads the deployment's OIDC token automatically. For local development, run `vercel link` followed by `vercel env pull` to download a short-lived token into `.env.local`.

## Adapter support

| Adapter                                 | Helper                   | Outbound field              |
| --------------------------------------- | ------------------------ | --------------------------- |
| [Slack](/adapters/official/slack)       | `connectSlackAdapter`    | `botToken`                  |
| [Discord](/adapters/official/discord)   | `connectDiscordAdapter`  | `botToken`, `applicationId` |
| [GitHub](/adapters/official/github)     | `connectGitHubAdapter`   | `installationToken`         |
| [Linear](/adapters/official/linear)     | `connectLinearAdapter`   | `accessToken`               |
| [Notion](/adapters/official/notion)     | `connectNotionAdapter`   | `token`                     |
| [Telegram](/adapters/official/telegram) | `connectTelegramAdapter` | `botToken`                  |

Each helper accepts `(connector, params?, options?)`, where `params` is the [`getToken`](https://vercel.com/docs/connect/ts-sdk-reference) parameters minus `subject` (pinned to `{ type: "app" }`), letting you pass through `installationId`, `scopes`, or `validityBufferMs`.

## Set up a connector

The trigger-forwarding steps below apply to Slack, Discord, GitHub, and Linear.
For Notion and Telegram, create and attach the connector without triggers, then
use native webhook verification or polling.

1. Create a connector for the provider in the [Vercel dashboard](https://vercel.com/d?to=%2F%5Bteam%5D%2F~%2Fconnect) or with the CLI, enabling trigger forwarding so inbound webhooks reach your project:

```bash
vercel connect create slack --name acme-slack --triggers
```

2. Attach your project and register your Chat SDK webhook route (`/api/webhooks/{platform}`) as the trigger destination:

```bash
vercel connect attach slack/acme-slack \
  --project my-bot --environment production \
  --triggers --trigger-path /api/webhooks/slack
```

3. Pull a development token locally (deployments get `VERCEL_OIDC_TOKEN` automatically):

```bash
vercel link
vercel env pull
```

## Wire up the adapter

Spread the helper into the adapter factory. The webhook route is unchanged — Connect forwards verified events to the same handler.

```typescript title="lib/bot.ts" lineNumbers
import { Chat } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createRedisState } from "@chat-adapter/state-redis";
import { connectSlackAdapter } from "@vercel/connect/chat";

export const bot = new Chat({
  userName: "mybot",
  adapters: {
    slack: createSlackAdapter({
      ...connectSlackAdapter("slack/acme-slack"),
    }),
  },
  state: createRedisState(),
});
```

Replace `slack/acme-slack` with your connector UID from the Connect dashboard or `vercel connect list`. Omit `signingSecret` / `SLACK_SIGNING_SECRET` when using the helper — the OIDC `webhookVerifier` is the freshness boundary.

### Discord

```typescript title="lib/bot.ts" lineNumbers
import { createDiscordAdapter } from "@chat-adapter/discord";
import { connectDiscordAdapter } from "@vercel/connect/chat";

createDiscordAdapter({
  ...connectDiscordAdapter("discord/acme-discord"),
});
```

The helper resolves `botToken` and `applicationId` from one Connect token
response. Omit `DISCORD_BOT_TOKEN`, `DISCORD_PUBLIC_KEY`, and
`DISCORD_APPLICATION_ID` — Connect OIDC verification replaces Discord's
Ed25519 public-key check for trigger-forwarded interactions.

### GitHub

```typescript title="lib/bot.ts" lineNumbers
import { createGitHubAdapter } from "@chat-adapter/github";
import { connectGitHubAdapter } from "@vercel/connect/chat";

createGitHubAdapter({
  ...connectGitHubAdapter("github/acme-github"),
  userName: "my-bot[bot]",
});
```

`installationToken` is the installation access token a GitHub App would normally mint via its private-key JWT exchange — the adapter uses it directly and skips that exchange.

### Linear

```typescript title="lib/bot.ts" lineNumbers
import { createLinearAdapter } from "@chat-adapter/linear";
import { connectLinearAdapter } from "@vercel/connect/chat";

createLinearAdapter({
  ...connectLinearAdapter("linear/acme-linear"),
  mode: "agent-sessions",
});
```

Use `mode: "agent-sessions"` for app-actor installs. For outbound calls outside webhook handling (cron jobs, workflows), wrap them in `withInstallation()` so a request-scoped client is bound:

```typescript title="lib/jobs.ts" lineNumbers
await linear.withInstallation("org-id", async () => {
  await linear.postMessage("linear:issue-id", "Hello from a background job");
});
```

### Notion

```typescript title="lib/bot.ts" lineNumbers
import { createNotionAdapter } from "@chat-adapter/notion";
import { connectNotionAdapter } from "@vercel/connect/chat";

createNotionAdapter({
  ...connectNotionAdapter("notion/acme-notion"),
  verificationToken: process.env.NOTION_VERIFICATION_TOKEN,
});
```

`connectNotionAdapter` supplies only the outbound `token`; it does not include a
`webhookVerifier`. Connect does not forward Notion triggers, so configure the
webhook subscription directly in Notion and retain
`NOTION_VERIFICATION_TOKEN` for native HMAC verification. Omit
`NOTION_TOKEN` when using the helper.

### Telegram

```typescript title="lib/bot.ts" lineNumbers
import { createTelegramAdapter } from "@chat-adapter/telegram";
import { connectTelegramAdapter } from "@vercel/connect/chat";

createTelegramAdapter({
  ...connectTelegramAdapter("telegram/acme-telegram"),
  secretToken: process.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,
});
```

`connectTelegramAdapter` supplies only the outbound `botToken`; it does not
include a `webhookVerifier`. The adapter derives webhook deduplication scope
from Telegram's stable bot identity, not the rotating credential. Retain
`TELEGRAM_WEBHOOK_SECRET_TOKEN` for native webhook verification or use polling
mode. Omit `TELEGRAM_BOT_TOKEN` when using the helper.

## Custom webhook verification

Each trigger-capable helper attaches a default verifier that matches the deployment's project and environment automatically (`projectId` defaults to `VERCEL_PROJECT_ID`, `environment` to `VERCEL_TARGET_ENV` then `VERCEL_ENV`), so production, preview, and development each accept only their own tokens. Verification fails closed — if those values are absent, every request is rejected, and the issuer is pinned to `https://oidc.vercel.com`.

To add constraints (for example to accept multiple environments), build a verifier with `createConnectWebhookVerifier` and override the field:

```typescript title="lib/bot.ts" lineNumbers
import {
  connectSlackAdapter,
  createConnectWebhookVerifier,
} from "@vercel/connect/chat";

createSlackAdapter({
  ...connectSlackAdapter("slack/acme-slack"),
  webhookVerifier: createConnectWebhookVerifier({
    environment: ["production", "preview"],
  }),
});
```

<Callout type="warn">
  Avoid hardcoding `environment: "production"` unless you only forward to production — it would reject preview and development deployments.
</Callout>

## Notes and limitations

* **App-scoped tokens.** The helpers act as the application itself (`subject: { type: "app" }`). End-user OAuth is a separate concern.
* **Freshness and replay.** OIDC verification replaces each provider's native signature (and timestamp) check, so request freshness relies on the short-lived OIDC token's expiry rather than a signed timestamp, and there is no built-in delivery de-duplication. Keep your webhook handlers idempotent.
* **Socket Mode is incompatible.** Connect trigger forwarding is HTTP-only; it doesn't apply to the Slack adapter's Socket Mode.
* **Testing.** Connect forwards to deployed URLs, not `localhost` — test against a preview or development deployment.

## Related resources

* [Vercel Connect overview](https://vercel.com/docs/connect)
* [Vercel Connect triggers](https://vercel.com/docs/connect/concepts/triggers)
* [`@vercel/connect` SDK reference](https://vercel.com/docs/connect/ts-sdk-reference)


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)