@chat-adapter/discord
v4.33.0
Published
Discord adapter for Chat SDK — HTTP interactions, Gateway events, slash commands, and embeds
Readme
@chat-adapter/discord
npm package:
@chat-adapter/discord
Discord adapter for Chat SDK. Configure with HTTP Interactions and Gateway WebSocket support.
Documentation: chat-sdk.dev/adapters/official/discord · Guides: vercel.com/kb/chat-sdk
Installation
pnpm add @chat-adapter/discordScaffold with the CLI
To scaffold a new Discord bot with this adapter preselected:
npx create-chat-sdk@latest my-bot --adapter discord memoryVisit the adapters directory to see other available official and vendor-official adapters.
Usage
The adapter auto-detects DISCORD_BOT_TOKEN, DISCORD_PUBLIC_KEY, DISCORD_APPLICATION_ID, and DISCORD_MENTION_ROLE_IDS from environment variables:
import { Chat } from "chat";
import { createDiscordAdapter } from "@chat-adapter/discord";
const bot = new Chat({
userName: "mybot",
adapters: {
discord: createDiscordAdapter(),
},
});
bot.onNewMention(async (thread, message) => {
await thread.post("Hello from Discord!");
});Discord application setup
1. Create application
- Go to the Discord Developer Portal
- Click New Application and give it a name
- Note the Application ID from the General Information page
- Copy the Public Key from the General Information page
2. Create bot
- Go to the Bot section in the left sidebar
- Click Reset Token to generate a new bot token
- Copy and save the token (you won't see it again)
- Enable these Privileged Gateway Intents:
- Message Content Intent
- Server Members Intent (if needed)
3. Configure interactions endpoint
- Go to General Information
- Set Interactions Endpoint URL to
https://your-domain.com/api/webhooks/discord - Discord sends a PING to verify the endpoint
4. Add bot to server
- Go to OAuth2 then URL Generator
- Select scopes:
bot,applications.commands - Select bot permissions: Send Messages, Send Messages in Threads, Create Public Threads, Read Message History, Add Reactions, Attach Files
- Copy the generated URL and open it to invite the bot to your server
Architecture: HTTP Interactions vs Gateway
Discord has two ways to receive events:
HTTP Interactions (default):
- Receives button clicks, slash commands, and verification pings
- Works out of the box with serverless
- Does not receive regular messages
Gateway WebSocket (required for messages):
- Receives regular messages and reactions
- Receives slash commands and button clicks when no Interactions Endpoint URL is configured
- Requires a persistent connection
- In serverless environments, use a cron job to maintain the connection
Discord sends interactions through either the Gateway or an Interactions Endpoint URL, not both. Use the HTTP endpoint for serverless apps. For resident gateway-only apps, leave the Interactions Endpoint URL unset and start the Gateway listener without webhookUrl so interactions are processed directly.
Gateway setup for serverless
1. Create Gateway route
import { after } from "next/server";
import { bot } from "@/lib/bot";
export const maxDuration = 800;
export async function GET(request: Request): Promise<Response> {
const cronSecret = process.env.CRON_SECRET;
if (!cronSecret) {
return new Response("CRON_SECRET not configured", { status: 500 });
}
const authHeader = request.headers.get("authorization");
if (authHeader !== `Bearer ${cronSecret}`) {
return new Response("Unauthorized", { status: 401 });
}
const durationMs = 600 * 1000;
const webhookUrl = `https://${process.env.VERCEL_URL}/api/webhooks/discord`;
await bot.initialize();
const discord = bot.getAdapter("discord");
return discord.startGatewayListener(
{ waitUntil: (task) => after(() => task) },
durationMs,
undefined,
webhookUrl
);
}2. Configure Vercel Cron
{
"crons": [
{
"path": "/api/discord/gateway",
"schedule": "*/9 * * * *"
}
]
}This runs every 9 minutes, ensuring overlap with the 10-minute listener duration.
3. Add environment variables
Add CRON_SECRET to your Vercel project settings.
Role mentions
By default, only direct user mentions (@BotName) trigger onNewMention handlers. To also trigger on role mentions (e.g., @AI):
- Create a role in your Discord server (e.g., "AI")
- Assign the role to your bot
- Copy the role ID (right-click role in server settings with Developer Mode enabled)
- Add to
mentionRoleIds:
createDiscordAdapter({
mentionRoleIds: ["1457473602180878604"],
});Or set DISCORD_MENTION_ROLE_IDS as a comma-separated string in your environment variables.
Interaction flags
Discord interactions return a transient "thinking..." message, which then gets replaced with your content. Because of Discord's API, your message's ephemerality must be set on this initial response, not later in an onSlashCommand handler.
Use the interactionFlags option to make the loading state and your custom response visible only to the user who invoked the command:
import {
createDiscordAdapter,
DiscordInteractionResponseFlag,
} from "@chat-adapter/discord";
createDiscordAdapter({
interactionFlags: ({ command }) => {
if (command === "/admin") {
return DiscordInteractionResponseFlag.Ephemeral;
}
},
});Later calls to event.channel.post() will share the same ephemeral message.
Calls to event.channel.postEphemeral() will fallback to a private DM.
Configuration
All options are auto-detected from environment variables when not provided.
| Option | Required | Description |
|--------|----------|-------------|
| botToken | No* | Discord bot token. Auto-detected from DISCORD_BOT_TOKEN |
| publicKey | No* | Application public key. Auto-detected from DISCORD_PUBLIC_KEY |
| applicationId | No* | Discord application ID. Auto-detected from DISCORD_APPLICATION_ID |
| mentionRoleIds | No | Array of role IDs that trigger mention handlers. Auto-detected from DISCORD_MENTION_ROLE_IDS (comma-separated) |
| interactionFlags | No | Function returning Discord interaction flags for the initial deferred slash command response |
| apiUrl | No | Override the Discord API base URL. Auto-detected from DISCORD_API_URL |
| logger | No | Logger instance (defaults to ConsoleLogger("info")) |
*botToken, publicKey, and applicationId are required — either via config or env vars.
Environment variables
DISCORD_BOT_TOKEN=your-bot-token
DISCORD_PUBLIC_KEY=your-application-public-key
DISCORD_APPLICATION_ID=your-application-id
DISCORD_MENTION_ROLE_IDS=1234567890,0987654321 # Optional
DISCORD_API_URL=... # Optional, override the Discord API base URL
CRON_SECRET=your-random-secret # For Gateway cronFeatures
Messaging
| Feature | Supported | |---------|-----------| | Post message | Yes | | Edit message | Yes | | Delete message | Yes | | File uploads | Yes | | Streaming | Post+Edit fallback |
Rich content
| Feature | Supported | |---------|-----------| | Card format | Embeds | | Buttons | Yes | | Link buttons | Yes | | Select menus | No | | Tables | GFM | | Fields | Yes | | Images in cards | Yes | | Modals | No |
Conversations
| Feature | Supported | |---------|-----------| | Slash commands | Yes | | Mentions | Yes | | Add reactions | Yes | | Remove reactions | Yes | | Typing indicator | Yes | | DMs | Yes | | Ephemeral messages | No (DM fallback) |
Message history
| Feature | Supported | |---------|-----------| | Fetch messages | Yes | | Fetch single message | No | | Fetch thread info | Yes | | Fetch channel messages | Yes | | List threads | Yes | | Fetch channel info | Yes | | Post channel message | Yes |
Testing
Run a local tunnel (e.g., ngrok) to test webhooks locally:
ngrok http 3000Update the Interactions Endpoint URL in the Discord Developer Portal to your ngrok URL.
Troubleshooting
Bot not responding to messages
- Check Gateway connection: Messages require the Gateway WebSocket, not just HTTP interactions
- Verify Message Content Intent: Enable this in the Bot settings
- Check bot permissions: Ensure the bot can read messages in the channel
Role mentions not triggering
- Verify role ID: Enable Developer Mode in Discord settings, then right-click the role
- Check
mentionRoleIdsconfig: Ensure the role ID is in the array - Confirm bot has the role: The bot must have the role assigned
Signature verification failing
- Check public key format: Should be a 64-character hex string (lowercase)
- Verify endpoint URL: Must exactly match what's configured in Discord Developer Portal
- Check for body parsing: Don't parse the request body before verification
Resources
- Create a Discord support bot with Nuxt and Redis — Walks through building a Discord support bot with Nuxt, covering project setup, Discord app configuration, Gateway forwarding, AI-powered responses, and deployment.
See all guides and templates at chat-sdk.dev/resources.
AI Coding Agents
If you use an AI coding agent such as OpenAI Codex, Claude Code, or Cursor, install the Chat SDK skill so it knows the SDK APIs, adapter patterns, and project conventions before writing code.
npx skills add vercel/chatThe skill references bundled documentation in node_modules/chat/docs, plus adapter guides and starter templates in the published package.
You can also install the Vercel Plugin for a broader agent toolkit — it includes the Chat SDK skill alongside specialist agents, agent slash commands, and more:
npx plugins add vercel/vercel-pluginThe plugin is optional; the skill alone is enough to build with Chat SDK.
For agent-readable documentation, see chat-sdk.dev/llms.txt (page index) or chat-sdk.dev/llms-full.txt (full text).
License
MIT
