Vercel

Slash Commands

Handle slash command invocations and respond with messages or modals.

Slash commands let users invoke your bot with /command syntax. Register handlers with onSlashCommand to respond.

Slash commands are supported on Slack and Discord.

Handle a specific command

lib/bot.ts
bot.onSlashCommand("/status", async (event) => {
  await event.channel.post("All systems operational!");
});

Handle multiple commands

lib/bot.ts
bot.onSlashCommand(["/help", "/info"], async (event) => {
  await event.channel.post(`You invoked ${event.command}`);
});

Catch-all handler

Register a handler without a command to catch all slash commands:

lib/bot.ts
bot.onSlashCommand(async (event) => {
  console.log(`Command: ${event.command}, Args: ${event.text}`);
});

SlashCommandEvent

The event object passed to slash command handlers:

PropertyTypeDescription
commandstringThe command name (e.g., /status)
textstringArguments after the command
userAuthorThe user who invoked the command
channelChannelThe channel where the command was invoked
adapterAdapterThe platform adapter
triggerIdstring (optional)Platform trigger ID for opening modals
openModal(modal) => Promise<{ viewId: string } | undefined>Open a modal dialog
rawunknownPlatform-specific payload

Respond to a command

Use event.channel to post messages:

lib/bot.ts
bot.onSlashCommand("/greet", async (event) => {
  // Public message to the channel
  await event.channel.post(`Hello, ${event.user.fullName}!`);

  // Ephemeral message (only visible to the user)
  await event.channel.postEphemeral(
    event.user,
    "This message is just for you!",
    { fallbackToDM: false }
  );
});

Open a modal

Use event.openModal() to open a modal in response to a slash command:

lib/bot.tsx
import { Modal, TextInput, Select, SelectOption } from "chat";

bot.onSlashCommand("/feedback", async (event) => {
  const result = await event.openModal(
    <Modal callbackId="feedback_form" title="Send Feedback" submitLabel="Send">
      <TextInput id="message" label="Your Feedback" multiline />
      <Select id="category" label="Category">
        <SelectOption label="Bug" value="bug" />
        <SelectOption label="Feature" value="feature" />
      </Select>
    </Modal>
  );

  if (!result) {
    await event.channel.post("Couldn't open the feedback form. Please try again.");
  }
});

When a modal is opened from a slash command, the submit handler receives relatedChannel instead of relatedThread. Use this to post back to the channel where the command was invoked.

lib/bot.ts
bot.onModalSubmit("feedback_form", async (event) => {
  const { message, category } = event.values;

  // Post to the channel where the slash command was invoked
  if (event.relatedChannel) {
    await event.relatedChannel.post(`Feedback received! Category: ${category}`);
  }
});

Discord

Discord slash commands are received via HTTP Interactions — no Gateway connection is needed. The adapter automatically sends a deferred response to Discord, then resolves it when your handler calls event.channel.post().

Subcommands

Discord supports subcommand groups and subcommands. The adapter flattens these into the event.command path:

Discord commandevent.commandevent.text
/status/status""
/project create --name="Acme"/project createAcme
/project issue list --status="open"/project issue listopen

For full option details (names, types), use event.raw to access the original Discord interaction payload.

Registering commands with Discord

You need to register slash commands with the Discord API before they appear in the client. The Chat SDK handles incoming commands but does not register them for you.