Chat SDK with Vercel Connect
Vercel Connect is available on all plans and is subject to the Vercel Connect terms
The @vercel/connect/chat entry point connects Vercel Connect credentials to
the Chat SDK adapter for each
supported platform.
The helpers configure outbound and inbound requests separately:
- Outbound provider API requests: Each credential field is an async
resolver. The adapter calls it when it needs a provider credential.
@vercel/connecthandles caching and refreshes short-lived tokens. - Inbound provider webhooks: Slack, Discord, Microsoft Teams, GitHub, and Linear can use
Connect triggers. Connect verifies the
provider's request, forwards it, and adds a Vercel OpenID Connect
(OIDC) bearer token. The helper's
webhookVerifierverifies that OIDC token instead of performing the provider's native verification.
The inbound verifier does not verify provider signatures or Microsoft's native JWT itself. Only use it for requests forwarded through a Connect trigger.
| Platform | Helper | Outbound fields | Inbound verification |
|---|---|---|---|
| Slack | connectSlackAdapter | botToken | Connect trigger and Vercel OIDC |
| Discord | connectDiscordAdapter | botToken, applicationId | Connect trigger and Vercel OIDC |
| Microsoft Teams | connectTeamsAdapter | appId, token | Connect trigger and Vercel OIDC |
| GitHub | connectGitHubAdapter | installationToken | Connect trigger and Vercel OIDC |
| Linear | connectLinearAdapter | accessToken | Connect trigger and Vercel OIDC |
| Notion | connectNotionAdapter | token | Direct Notion webhook and NOTION_VERIFICATION_TOKEN |
| Telegram | connectTelegramAdapter | botToken | Direct Telegram webhook secret or polling |
All helpers request app-subject credentials with
subject: { type: 'app' }. They do not request credentials on behalf of an
end user.
The following example connects a Slack app. Replace slack with discord,
github, linear, or microsoft-teams for another trigger-capable platform.
For Microsoft Teams, use a connector UID such as microsoft-teams/acme-teams
and the webhook route /api/webhooks/teams for bot.webhooks.teams.
-
Create the connector and enable triggers:
terminalvercel connect create slack --name acme-slack --triggers -
Attach it to your project. Set the trigger path to the matching Chat SDK webhook route:
terminalvercel connect attach slack/acme-slack \ --project my-bot \ --environment production \ --triggers \ --trigger-path /api/webhooks/slackThe path must match the route where you expose
bot.webhooks.<platform>. See thevercel connectCLI reference for Preview branches and Custom Environments. -
Link your local directory and pull a development OIDC token:
terminalvercel link vercel env pullVercel deployments receive
VERCEL_OIDC_TOKENautomatically. Connect forwards webhooks to deployed URLs, notlocalhost. -
Spread the Connect config into the adapter:
app/chat.tsimport { createSlackAdapter } from '@chat-adapter/slack'; import { connectSlackAdapter } from '@vercel/connect/chat'; import { Chat } from 'chat'; export const bot = new Chat({ userName: 'my-bot', adapters: { slack: createSlackAdapter({ ...connectSlackAdapter('slack/acme-slack'), }), }, });
Keep your existing Chat SDK webhook route. Connect sends the forwarded request
to the path you registered during vercel connect attach.
Pass requested provider scopes as the helper's second argument:
import { createSlackAdapter } from '@chat-adapter/slack';
import { connectSlackAdapter } from '@vercel/connect/chat';
const slack = createSlackAdapter({
...connectSlackAdapter('slack/acme-slack', {
scopes: ['chat:write'],
}),
});Do not set signingSecret or SLACK_SIGNING_SECRET for a
Connect-triggered route. The adapter verifies the forwarded request's Vercel
OIDC token.
The helper resolves the bot token and application ID from one Connect token response:
import { createDiscordAdapter } from '@chat-adapter/discord';
import { connectDiscordAdapter } from '@vercel/connect/chat';
const discord = createDiscordAdapter({
...connectDiscordAdapter('discord/acme-discord'),
});Do not set DISCORD_BOT_TOKEN, DISCORD_APPLICATION_ID, or
DISCORD_PUBLIC_KEY for the Connect-backed fields and trigger route.
connectTeamsAdapter resolves the bot's appId during initialization and
supplies a scope-aware token callback for Bot Framework and Microsoft Graph:
import { createTeamsAdapter } from '@chat-adapter/teams';
import { connectTeamsAdapter } from '@vercel/connect/chat';
const teams = createTeamsAdapter({
...connectTeamsAdapter('microsoft-teams/acme-teams'),
});import { createTeamsAdapter } from '@chat-adapter/teams';
import { connectTeamsAdapter } from '@vercel/connect/chat';
const teams = createTeamsAdapter({
...connectTeamsAdapter('microsoft-teams/acme-teams'),
});Omit TEAMS_APP_ID and TEAMS_APP_PASSWORD when using the helper. Enable
trigger forwarding to /api/webhooks/teams; the helper verifies forwarded
requests with Vercel OIDC instead of Microsoft's native JWT.
The token callback requests separate tokens for
https://api.botframework.com/.default and
https://graph.microsoft.com/.default. Graph reads still require the
appropriate installation and consent permissions. Connect uses the bot's
home tenant for managed tokens.
Chat initializes the adapter automatically before handling webhooks. Call
await bot.initialize() before using adapter methods directly, because the
appId resolver runs during initialization.
The adapter receives an installation access token directly, so it does not perform a private-key JSON Web Token exchange:
import { createGitHubAdapter } from '@chat-adapter/github';
import { connectGitHubAdapter } from '@vercel/connect/chat';
const github = createGitHubAdapter({
...connectGitHubAdapter('github/acme-github'),
userName: 'my-bot[bot]',
});Use the agent sessions mode for an app-actor installation:
import { createLinearAdapter } from '@chat-adapter/linear';
import { connectLinearAdapter } from '@vercel/connect/chat';
const linear = createLinearAdapter({
...connectLinearAdapter('linear/acme-linear'),
mode: 'agent-sessions',
});Notion support is outbound-only. Create and attach the connector without
--triggers:
vercel connect create notion --name acme-notion
vercel connect attach notion/acme-notion --project my-botConfigure the webhook directly in Notion. Keep Notion's native verification token for inbound HMAC verification:
import { createNotionAdapter } from '@chat-adapter/notion';
import { connectNotionAdapter } from '@vercel/connect/chat';
const notion = createNotionAdapter({
...connectNotionAdapter('notion/acme-notion'),
verificationToken: process.env.NOTION_VERIFICATION_TOKEN,
});The helper supplies token, so you can omit NOTION_TOKEN. It does not
supply a webhookVerifier.
Telegram support is outbound-only. Create and attach the connector without
--triggers:
vercel connect create telegram --name acme-telegram
vercel connect attach telegram/acme-telegram --project my-botKeep Telegram's native webhook secret, or use polling mode without an inbound webhook:
import { createTelegramAdapter } from '@chat-adapter/telegram';
import { connectTelegramAdapter } from '@vercel/connect/chat';
const telegram = createTelegramAdapter({
...connectTelegramAdapter('telegram/acme-telegram'),
secretToken: process.env.TELEGRAM_WEBHOOK_SECRET_TOKEN,
});The helper supplies botToken, so you can omit TELEGRAM_BOT_TOKEN. It does
not supply a webhookVerifier.
Each helper accepts Connect token parameters as its second argument. You can
pass scopes, installationId, and validityBufferMs. You cannot override
the app subject.
Use installationId when one connector has several provider installations:
const slack = createSlackAdapter({
...connectSlackAdapter('slack/acme-slack', {
installationId: 'sci_123',
scopes: ['chat:write'],
}),
});If you omit installationId, Connect uses the connector's default
installation. The helpers do not automatically select an installation from an
inbound workspace or organization. See Installations
and Tokens for selection and scope behavior.
The default verifier accepts a token only when its project and environment
match the current deployment. It reads the project from VERCEL_PROJECT_ID
and the environment from VERCEL_TARGET_ENV, then VERCEL_ENV.
Use createConnectWebhookVerifier to accept additional environments or pin an
explicit project:
import { createSlackAdapter } from '@chat-adapter/slack';
import {
connectSlackAdapter,
createConnectWebhookVerifier,
} from '@vercel/connect/chat';
const slack = createSlackAdapter({
...connectSlackAdapter('slack/acme-slack'),
webhookVerifier: createConnectWebhookVerifier({
environment: ['production', 'preview'],
}),
});The verifier fails closed when it cannot determine a project or environment.
Do not pin it to production if a Preview deployment must receive triggers.
- Preview deployments: Register a Preview branch as the trigger
destination and allow
previewin a custom verifier. Connect cannot forward tolocalhost. - Freshness and idempotency: OIDC token expiry provides request freshness. The verifier does not provide nonce or delivery deduplication. Providers and Connect can retry requests, so make every handler idempotent.
- Slack Socket Mode: Connect trigger forwarding uses HTTP. It does not work with the Slack adapter's Socket Mode.
- Installation routing: The helpers use one configured or default installation. They do not derive a tenant-specific installation from each inbound event.
Deploy a Chat SDK template to start building AI agents that use Vercel Connect to securely access third-party services and APIs:
- Review Connect triggers to choose a destination.
- Review Authentication to understand deployment OIDC tokens.
- Use the SDK reference for token parameters and errors.
Was this helpful?


