惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
B
Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
GbyAI
GbyAI
IT之家
IT之家
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
博客园_首页
C
Check Point Blog
博客园 - 【当耐特】
美团技术团队
Last Week in AI
Last Week in AI
A
About on SuperTechFans
雷峰网
雷峰网
MongoDB | Blog
MongoDB | Blog
Microsoft Azure Blog
Microsoft Azure Blog
M
MIT News - Artificial intelligence
Martin Fowler
Martin Fowler
J
Java Code Geeks
B
Blog RSS Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
Google Developers Blog
F
Fortinet All Blogs

Chat SDK Documentation

History | Chat SDK History | Chat SDK List a vendor-official adapter | Chat SDK Approvals | Chat SDK Vercel Connect | Chat SDK Teams Low-Level APIs | Chat SDK CLI | Chat SDK Platform Adapters | Chat SDK State Adapters | Chat SDK Cards | Chat SDK Getting Started | Chat SDK Introduction | Chat SDK Modals | Chat SDK Slack Low-Level APIs | Chat SDK Streaming | Chat SDK Testing | Chat SDK Overview | Chat SDK toAiMessages | Chat SDK Cards | Chat SDK Overview | Chat SDK Markdown | Chat SDK Modals | Chat SDK AI SDK Tools | Chat SDK Types | Chat SDK Message Subject | Chat SDK Conversation History | Chat SDK Transcripts | Chat SDK Slack bot with Next.js and Redis Direct Messages | Chat SDK Emoji | Chat SDK
Actions | Chat SDK
Vercel · 2026-04-06 · via Chat SDK Documentation

Handle button clicks and interactive card events across platforms.

Actions let you handle button clicks, dropdown selections, and other interactive events from cards. Register handlers with onAction to respond when users interact with your cards.

bot.onAction("approve", async (event) => {
  await event.thread.post(`Order approved by ${event.user.fullName}!`);
});
bot.onAction(["approve", "reject"], async (event) => {
  const action = event.actionId === "approve" ? "approved" : "rejected";
  await event.thread.post(`Order ${action} by ${event.user.fullName}`);
});

Register a handler without an action ID to catch all actions:

bot.onAction(async (event) => {
  console.log(`Action: ${event.actionId}, Value: ${event.value}`);
});

The event object passed to action handlers:

PropertyTypeDescription
actionIdstringThe id from the Button or Select component
valuestring (optional)The value from the Button or selected option
userAuthorThe user who clicked
threadThread | nullThe thread containing the card (null for view-based actions like home tab buttons)
messageIdstringThe message containing the card
threadIdstringThread ID
adapterAdapterThe platform adapter
triggerIdstring (optional)Platform trigger ID (used for opening modals)
openModal(modal) => Promise<void>Open a modal dialog
rawunknownPlatform-specific event payload

Use the value prop on buttons to pass extra context to your handler:

<Button id="report" value="bug">Report Bug</Button>
<Button id="report" value="feature">Request Feature</Button>
bot.onAction("report", async (event) => {
  if (event.value === "bug") {
    // Open bug report flow
  } else if (event.value === "feature") {
    // Open feature request flow
  }
});

Use event.openModal() to open a modal in response to a button click:

import { Modal, TextInput, Select, SelectOption } from "chat";

bot.onAction("feedback", async (event) => {
  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>
  );
});

Modals are currently supported on Slack and Teams. Other platforms will receive a no-op or fallback behavior.

Buttons accept a callbackUrl prop. When clicked, the action data is POSTed to that URL in addition to firing any onAction handler. This pairs naturally with webhook-based workflow engines to build approval flows without any onAction handler at all:

bot.onNewMention(async (thread) => {
  const approveUrl = "https://example.com/webhook/approve";
  const denyUrl = "https://example.com/webhook/deny";

  await thread.post(
    <Card title="Deploy v2.4.1?">
      <Actions>
        <Button callbackUrl={approveUrl} id="approve" style="primary">
          Approve
        </Button>
        <Button callbackUrl={denyUrl} id="deny" style="danger">
          Deny
        </Button>
      </Actions>
    </Card>
  );
});

Callback payload

The POST body sent to the callbackUrl:

{
  "type": "action",
  "actionId": "approve",
  "user": { "id": "U123", "name": "alice" },
  "threadId": "slack:C123:1234567890.123",
  "messageId": "1234567890.456"
}

If the button also has a value prop, it is included in the payload as "value".

Platform limits apply to encoded button data. Discord's custom_id has a 100 character limit - if the action ID plus callback token exceed this, posting the card throws a ValidationError. Telegram's callback_data has a 64 byte limit - buttons that exceed this will throw a ValidationError. Keep action IDs short when using callbackUrl on these platforms.

For modals, see callbackUrl on modals.