Zoom Team Chat 消息卡片结构详解:Chatbot API 富交互消息的 JSON 设计与实战
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
导读
本文聚焦 Zoom Team Chat 集成中 Chatbot API(机器人类型)的核心能力——消息卡片(Message Card),讲解其类卡片 JSON 结构(content.head与content.body)的完整设计、全部组件类型、交互机制与常见坑点。阅读后你将能独立构造包含标题、文本、键值字段、按钮、下拉框、表单与图片附件的富交互消息,并通过POST /v2/im/chat/messages发送给用户,再借助interactive_message_actions交互 Webhook 处理用户点击。相关权威素材见 Message Card Components Reference 与 Message Card Structure(概念文档)。
一、消息卡片的高层形态
Zoom Team Chat 的 Chatbot 消息使用一种"卡片化"的 JSON 结构(业界常称 message cards)。与 Team Chat API(用户类型,走POST /v2/chat/users/me/messages,发送纯文本message字段)不同,Chatbot API 发送的是结构化content对象,这是富交互能力的根基。
从 message-structure.md 可以看到核心骨架:
content.head → 标题 + 可选副标题 content.body → 组件数组(blocks) ├── message 文本块 ├── fields 键/值行 ├── actions 按钮块 └── attachments 图片/链接块对应的最小 JSON 骨架如下(来自 message-cards.md):
{ "content": { "head": { // 可选头部 "text": "Title", "sub_head": { "text": "Subtitle" } }, "body": [ // 组件数组 { "type": "message", "text": "Content" }, { "type": "actions", "items": [...] } // ... 更多组件 ] } }要点:
head是可选头部,text为主标题,sub_head.text为副标题;body是组件数组,每个元素通过type字段声明类型,可自由组合、有序排列;head与body可同时省略其一,但实际使用中至少应包含body,否则卡片没有可展示内容。
二、组件目录(Components Catalog)
2.1 文本类组件
message—— 纯文本内容:
{ "type": "message", "text": "Hello, this is plain text" }header—— 带可选样式的标题文本:
{ "type": "header", "text": "Main Heading", "style": { "bold": true, "italic": false } }styled_text—— 支持 Markdown 风格样式的文本(**Bold**加粗、*italic*斜体、`code`行内代码):
{ "type": "styled_text", "text": "**Bold** *italic* `code`" }2.2 交互类组件
actions(按钮)—— 可点击按钮,点击后触发交互 Webhook:
{ "type": "actions", "items": [ { "text": "Approve", "value": "approve", "style": "Primary" // Primary, Danger, Default }, { "text": "Reject", "value": "reject", "style": "Danger" } ] }按钮样式(style)三选一:
Primary—— 蓝色按钮Danger—— 红色按钮Default—— 灰色按钮
dropdown—— 带选项的选择菜单:
{ "type": "dropdown", "select_items": [ { "text": "Option 1", "value": "opt1" }, { "text": "Option 2", "value": "opt2" } ] }form_field—— 文本输入框:
{ "type": "form_field", "editable": true, "text": "Enter your name" }2.3 布局类组件
section—— 组件分组,支持可选的彩色侧边栏(sidebar):
{ "type": "section", "sidebar_color": "#3b82f6", // Hex 颜色 "sections": [ { "type": "message", "text": "Grouped content" } ] }推荐语义化配色:
- Success(成功):
#10b981(绿色) - Error(错误):
#ef4444(红色) - Warning(警告):
#f59e0b(橙色) - Info(信息):
#3b82f6(蓝色)
fields—— 以列展示的键值对:
{ "type": "fields", "items": [ { "key": "Status", "value": "Active" }, { "key": "Priority", "value": "High" }, { "key": "Assignee", "value": "John Doe" } ] }divider—— 水平分隔线:
{ "type": "divider" }2.4 媒体类组件
attachments—— 带可选链接的图片:
{ "type": "attachments", "img_url": "https://example.com/image.jpg", "resource_url": "https://example.com/full-page", "information": { "title": { "text": "Image Title" }, "description": { "text": "Click to view" } } }三、完整实战示例
3.1 构建通知(Build Notification)
{ "content": { "head": { "text": "Build #123 Complete", "sub_head": { "text": "main branch" } }, "body": [ { "type": "section", "sidebar_color": "#10b981", "sections": [ { "type": "message", "text": "✅ Build completed successfully" } ] }, { "type": "fields", "items": [ { "key": "Branch", "value": "main" }, { "key": "Commit", "value": "abc123" }, { "key": "Duration", "value": "2m 34s" } ] }, { "type": "actions", "items": [ { "text": "View Logs", "value": "view_logs", "style": "Primary" }, { "text": "Deploy", "value": "deploy", "style": "Default" } ] } ] } }3.2 审批请求(Approval Request)
{ "content": { "head": { "text": "Expense Approval Required" }, "body": [ { "type": "message", "text": "John Doe submitted an expense report" }, { "type": "fields", "items": [ { "key": "Amount", "value": "$500.00" }, { "key": "Category", "value": "Travel" }, { "key": "Date", "value": "Feb 9, 2026" } ] }, { "type": "divider" }, { "type": "actions", "items": [ { "text": "Approve", "value": "approve_500", "style": "Primary" }, { "text": "Reject", "value": "reject_500", "style": "Danger" }, { "text": "View Details", "value": "details_500", "style": "Default" } ] } ] } }3.3 错误通知(Error Notification)
{ "content": { "head": { "text": "⚠️ Service Alert" }, "body": [ { "type": "section", "sidebar_color": "#ef4444", "sections": [ { "type": "message", "text": "Database connection failed" } ] }, { "type": "fields", "items": [ { "key": "Service", "value": "api-prod" }, { "key": "Error", "value": "Connection timeout" }, { "key": "Time", "value": "2026-02-09 18:30:00 UTC" } ] }, { "type": "actions", "items": [ { "text": "View Logs", "value": "logs", "style": "Primary" }, { "text": "Acknowledge", "value": "ack", "style": "Default" } ] } ] } }四、如何发送卡片消息:Chatbot API 调用
卡片 JSON 只是content字段,发送时需封装进 Chatbot API 请求体中。在 SKILL.md 与 chatbot-setup.md 中给出了完整调用范式:
const response = await fetch('https://api.zoom.us/v2/im/chat/messages', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, // client_credentials 换取 'Content-Type': 'application/json' }, body: JSON.stringify({ robot_jid: process.env.ZOOM_BOT_JID, // Marketplace → Features → Chatbot → Bot Credentials to_jid: payload.toJid, // 来自 Webhook payload account_id: payload.accountId, // 来自 Webhook payload content: { head: { text: 'Build Notification', sub_head: { text: 'CI/CD Pipeline' } }, body: [ { type: 'message', text: 'Deployment successful!' }, { type: 'fields', items: [ { key: 'Branch', value: 'main' }, { key: 'Commit', value: 'abc123' } ] }, { type: 'actions', items: [ { text: 'View Logs', value: 'view_logs', style: 'Primary' }, { text: 'Dismiss', value: 'dismiss', style: 'Default' } ] } ] } }) });字段说明:
robot_jid:机器人 JID,格式如v1abc123xyz@xmpp.zoom.us,在 Zoom Marketplace 的 Bot Credentials 中获取;to_jid/account_id:来自bot_notificationWebhook payload,用于定位接收者;content:即上文讲解的完整卡片对象;- 令牌获取:使用
client_credentials授权模式(POST https://zoom.us/oauth/token,grant_type=client_credentials,Basic Auth 携带CLIENT_ID:CLIENT_SECRET),对应 scope 为imchat:bot(自动添加)。
注意两种 API 不可混用:Team Chat API 走POST /v2/chat/users/me/messages发送的是用户身份的纯文本,不支持富卡片;只有 Chatbot API(/v2/im/chat/messages)支持按钮、表单、下拉框、图片等富交互组件。若选错类型,认证方式、scope、端点全家不匹配。参见 api-selection.md。
五、交互闭环:按钮点击与 value 路由
消息卡片的价值在于交互。在 message-structure.md 中明确强调:按钮必须携带一个可用于路由的value——当你收到交互 Webhook 时,正是靠它来区分用户点了哪个按钮。
交互流程(来自 button-actions.md):
- 你发送一张包含
actions.items[]的卡片,每个按钮带唯一value; - 用户点击后,Zoom 向你的 Bot Endpoint URL 发送
interactive_message_actionsWebhook; - 你的 handler 依据
actionItem.value路由处理。
路由建议使用稳定、语义化的 action ID,例如approve_request、reject_request、open_ticket:123,避免使用易变的展示文本做路由键。
服务端处理示例(来自 SKILL.md):
case 'interactive_message_actions': { const { actionItem, toJid, accountId } = payload; if (actionItem.value === 'approve') { await sendChatbotMessage(toJid, accountId, { body: [{ type: 'message', text: '✅ Approved!' }] }); } }在完整实现中(见 chatbot-setup.md 的utils/chatbot.js),还可以封装sendMessageWithButtons()帮助函数,把按钮数组批量映射为actions.items,并默认style: 'Default',从而保证每张卡片都能被统一、安全地构造。
六、组件限制(Limitations)
构造卡片前请务必对照容量上限,避免发送被拒或渲染异常:
| 组件 | 限制 |
|---|---|
| 消息文本 | 4,096 字符 |
| 按钮文本 | 40 字符 |
| 字段键/值 | 各 256 字符 |
| 下拉框选项 | 100 个 |
| 每条消息按钮 | 5 个 |
在 chatbot-setup.md 的utils/validation.js中还提供了一种防御性写法:发送前对文本执行trim()、移除控制字符(/[\x00-\x1F\x7F]/g)并substring(0, 4096)截断,从源头规避长度超限问题。
七、最佳实践
7.1 按钮文案设计
✅推荐:使用清晰、面向动作的标签
- "Approve Request"
- "View Details"
- "Cancel Order"
❌避免:语义模糊的标签
- "OK"
- "Click Here"
- "Button"
7.2 配色语义化
✅推荐:使用语义色
- 绿色(
#10b981)表示成功 - 红色(
#ef4444)表示错误/破坏性操作 - 蓝色(
#3b82f6)表示信息 - 橙色(
#f59e0b)表示警告
❌避免:无意义的随意配色。
7.3 字段格式
✅推荐:键保持简洁、值提供信息量:
{ "key": "Status", "value": "Active" }❌避免:键过长:
{ "key": "The current status of the request", "value": "Active" }八、常见坑与排障(Common Pitfalls)
message-structure.md 与 message-issues.md 共同总结了高频问题:
- 按钮缺少
value或 value 不可路由:交互 Webhook 到来时无法确定用户意图,导致点击无响应。务必为每个按钮设置稳定唯一的value。 - "Zoom 没有渲染我的卡片"往往是 JSON 形状非法:发送前先校验 payload。做法是先对照已知可用的示例精简到最小卡片,再逐步增量添加组件,定位出错的组件。
- 消息发不出去:确认使用的 API 与令牌匹配——Team Chat API 用用户 OAuth 令牌,Chatbot API 用机器人令牌并携带
robot_jid;确认ZOOM_BOT_JID与ZOOM_ACCOUNT_ID正确。 - 收到
endpoint.url_validation却校验失败:确保你的端点按规范返回plainToken+encryptedToken(用ZOOM_VERIFICATION_TOKEN做 HMAC-SHA256 加密)。 - Webhook 签名校验:所有交互请求都应校验
x-zm-signature头(v0:${timestamp}:${JSON.stringify(body)}的 HMAC-SHA256 摘要),防止伪造请求。
九、测试卡片与后续进阶
- 在线预览:可借助 Zoom 官方的 Team Chat App Card Builder(
appssdk.zoom.us/cardbuilder)预览卡片设计、测试布局、生成 JSON——发送前先用它验证结构是最稳妥的实践。 - 最小冒烟测试:参照 get-started.md 的第 4 步,先用
body: [{ type: 'message', text: '...' }]发送一条纯文本机器人消息,确认链路打通后再叠加按钮、表单等高级组件。 - 继续深入:处理按钮点击的完整工程见 button-actions.md;理解
bot_notification、interactive_message_actions、chat_message.submit等全部事件见 webhook-events.md;从零搭建带 Webhook、签名校验与命令路由的完整机器人见 chatbot-setup.md。
十、组件速查表
| 组件 | 用途 | 关键字段 |
|---|---|---|
header | 标题与副标题 | text、style |
message | 纯文本 | text |
fields | 键值对 | items[].key/value |
actions | 按钮 | items[].text/value/style |
section | 彩色侧边栏分组 | sidebar_color、sections |
attachments | 图片与链接 | img_url、resource_url |
divider | 水平分隔线 | 无 |
form_field | 文本输入 | editable、text |
dropdown | 选择菜单 | select_items[] |
date_picker | 日期选择 | — |
掌握"head + body 组件数组"这一核心形态,配合完整的组件目录、交互 Webhook 路由与容量限制,即可在 Zoom Team Chat 中构建出 CI/CD 通知、审批流、服务告警、LLM 对话助手等各类富交互机器人体验。
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考