# WhatsApp 互动消息

互动消息是正文加上一个可供收件人点击的元素：一个 WhatsApp 按钮、一个菜单、一个链接、一张卡片，或者一个请求收件人提供位置或联系方式的提示。如果模板回复意味着解析自由文本，那么一个 WhatsApp 菜单或一组 WhatsApp 按钮可以为收件人提供固定选项，并将你定义的值返回给你。本页介绍六种类型的共同之处；每种类型各自的页面介绍其传输格式和专属限制。

## 六种类型

| 类型                                                                                  | Bird `interactive.type`    | 头部                               | 底部 | 正文上限                |
| ------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------- | ---- | ----------------------- |
| [回复按钮](/docs/guides/whatsapp/message-types/interactive/reply-buttons)             | `button`                   | 文本、图片、视频、文档             | 是   | 1024                    |
| [列表菜单](/docs/guides/whatsapp/message-types/interactive/list-menus)                | `list`                     | 仅文本                             | 是   | 4096                    |
| [链接按钮](/docs/guides/whatsapp/message-types/interactive/cta-url-buttons)           | `cta_url`                  | 文本、图片、视频、文档             | 是   | 1024                    |
| [媒体轮播](/docs/guides/whatsapp/message-types/interactive/carousels)                 | `carousel`                 | 消息无头部；每张卡片可含图片或视频 | 否   | 消息 1024，每张卡片 160 |
| [位置请求](/docs/guides/whatsapp/message-types/interactive/location-requests)         | `location_request_message` | 无                                 | 否   | 1024                    |
| [联系方式请求](/docs/guides/whatsapp/message-types/interactive/contact-info-requests) | `request_contact_info`     | 无                                 | 否   | 1024                    |

所有类型均为自由格式：只能在开放的客服窗口内发送，Meta 不会像审核模板那样对其进行审核。

互动消息属于自由格式内容，因此受客服窗口规则约束：参阅[客服窗口](/docs/guides/whatsapp/message-types#the-customer-service-window)了解其含义以及窗口关闭时的返回结果。

每次互动发送还需要 `from`，即你的工作区拥有的号码。Bird 的托管号码无法用于此目的，因此互动发送需要先接入一个你自己的号码。

## 互动内容字段

`interactive` 是 `POST /v1/whatsapp/messages` 上互斥的内容字段之一，与 `template`、`text`、`image` 等并列：一次发送中只能存在其中之一。在 `interactive` 内部，`type` 指明这是六种变体中的哪一种，该变体自身的字段承载其余数据（`buttons`、`list`、`cta_url` 或 `cards`）。Schema 禁止出现其他变体的字段，因此在一次发送中混用两种变体会在到达处理器之前就验证失败。

关于请求信封、`202` 响应模型和安全重试，请参阅[发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp)，本页不再重复介绍。

以下是一条最简互动消息：在一次回复按钮发送中放置两个 WhatsApp 按钮，每次一种语言。

**TypeScript**

```typescript
const msg = await bird.whatsapp.send({
  to: "+15551234567",
  from: "+13124495648",
  interactive: {
    type: "button",
    body_text: "Your gardening workshop is scheduled for 9am tomorrow.",
    buttons: [
      { type: "quick_reply", quick_reply: { slug: "change-booking", text: "Change" } },
      { type: "quick_reply", quick_reply: { slug: "cancel-booking", text: "Cancel" } },
    ],
  },
});
console.log(msg.id, msg.status);
```

Examples: [TypeScript](/zh-sg/wendang/guides/whatsapp/message-types/interactive.ts.md) · [Python](/zh-sg/wendang/guides/whatsapp/message-types/interactive.py.md) · [Go](/zh-sg/wendang/guides/whatsapp/message-types/interactive.go.md) · [PHP](/zh-sg/wendang/guides/whatsapp/message-types/interactive.php.md) · [CLI](/zh-sg/wendang/guides/whatsapp/message-types/interactive.cli.md) · [MCP](/zh-sg/wendang/guides/whatsapp/message-types/interactive.mcp.md) · [cURL](/zh-sg/wendang/guides/whatsapp/message-types/interactive.curl.md)

## 按钮

六种类型中有四种包含按钮，它们都使用相同的结构：一个带判别字段的对象，其 `type` 为 `quick_reply` 或 `cta_url`，各自携带同名的嵌套字段。`quick_reply` 按钮携带 `slug` 和 `text`；`cta_url` 按钮携带 `text` 和 `url`。各类型接受的按钮形式如下：

- **回复按钮**仅发送 `quick_reply` 按钮，1 到 3 个。
- **链接按钮**只发送一个 `cta_url` 按钮。
- **媒体轮播**在每张卡片上放置按钮：一个 `cta_url` 按钮，或最多三个 `quick_reply` 按钮，且轮播中每张卡片必须一致。
- **列表菜单**使用分区内的行而非此按钮对象，详见其专属页面。

`quick_reply` 按钮的 `slug` 是你为该按钮设置的标识。它不会展示给收件人，收件人看到的只有它的 `text` 标签，而 `slug` 会在回复中原样回传。正是这个往返过程使回复可以关联到产生它的按钮，因此在这里统一说明一次，而不在每个子页面重复。

## 读取回复

点击按钮或选择菜单行会发送一条入站消息，携带一个 `interactive_reply` 对象。`interactive_reply.type` 为 `button` 或 `list`；无论是哪个，嵌套对象都携带你声明的 `slug` 和 `text`（即收件人实际看到的已点击标签）。两种请求类型（位置请求和联系方式请求）的回复方式不同：位置请求的回复是一条普通的入站[位置](/docs/guides/whatsapp/message-types/interactive/location-requests)消息，联系方式请求的回复是一条入站[联系人名片](/docs/guides/whatsapp/message-types/interactive/contact-info-requests)，而非 `interactive_reply`。

回复通过消息列表和 `GET /v1/whatsapp/messages/{id}` 到达你，与任何入站 WhatsApp 消息的方式相同。要在回复到达时立即处理而非轮询，请订阅 `whatsapp.received` webhook：其载荷携带 `interactive_reply`，因此已包含被点击的按钮或行。[接收互动回复](/docs/guides/whatsapp/receiving-whatsapp/interactive-replies)介绍了点击的读取结构、webhook 载荷以及到达其他字段的点击。

## 引用消息以关联回复

发送时的 `in_reply_to_message_id` 引用同一会话中的一条早期消息，每条消息（无论发送还是接收）在读取时都会回传该字段。它是双向共用的同一个字段。

此关联是非对称的。点击 WhatsApp 按钮或菜单行时会携带 Meta 自有的 `context`，因此 `in_reply_to_message_id` 可解析到提供该选项的消息。共享的联系人名片不携带 `context`，因此无法解析：你需要通过 `from` 和时间来关联联系方式请求的回复，而非依赖此字段。

解析通过消息上下文存储进行，未命中时会**省略**该字段而非返回一个值。这在传输层上与完全没有回复目标的回复无法区分。如果集成需要可靠的关联，不应仅依赖此字段：在发送时携带你自己的 `metadata`，然后基于它进行匹配。

消息可被引用的窗口限制为 15 天；超过后发送会返回 `404` [`E15071`](/docs/api/errors/E15071)，因为 Bird 不再持有引用所需的提供方 ID。[发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp#quoting-a-message)负责发送端字段的说明：其长度、解析方式和请求结构。

## 错误

三个错误码专用于互动内容。每个仅在包含其所检查字段的类型上触发，因此第四列标明了哪些类型会实际遇到该错误。

| 错误码                                                                         | 状态 | 触发条件                                               | 适用于                                                     |
| ------------------------------------------------------------------------------ | ---- | ------------------------------------------------------ | ---------------------------------------------------------- |
| [E15055 `WhatsAppInteractiveLimitExceeded`](/docs/api/errors/E15055)           | 422  | 消息超出其类型的限制；目前为列表各分区合计超过 10 行。 | 仅列表菜单                                                 |
| [E15056 `WhatsAppInteractiveDuplicateLabel`](/docs/api/errors/E15056)          | 422  | 同一消息中两个按钮或行使用了相同的标签。               | 任何包含带标签按钮或行的类型：回复按钮、列表菜单、媒体轮播 |
| [E15059 `WhatsAppInteractiveCarouselButtonsMismatch`](/docs/api/errors/E15059) | 422  | 轮播中的卡片未全部携带相同的按钮。                     | 仅媒体轮播                                                 |

每次互动发送也可能遇到任何 WhatsApp 发送都会遇到的错误：客服窗口已关闭、发送方缺失或无效、收件人无效或内容不明确。这些错误在所有 WhatsApp 内容类型中通用，并非互动消息特有；参阅[发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp)获取完整列表，此处不再重复。

## 后续步骤

- [发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp)：请求信封、`202` 模型和安全重试
- [WhatsApp 事件](/docs/guides/whatsapp/events)：通过 API 或 webhook 跟踪每条消息的投递状态
- [WhatsApp 模板](/docs/guides/whatsapp/templates)：窗口关闭后仍可发送的消息

## Related resources

- [Connecting WhatsApp to Bird: from buying a number to a live channel](/learn/whatsapp/connecting-whatsapp-to-bird) (video)
- [What is the 24-hour customer service window on WhatsApp?](/explained/whatsapp/what-is-the-24-hour-customer-service-window) (answer)
- [WhatsApp message builder](/tools/whatsapp-message-builder) (tool)
- [WhatsApp](/products/whatsapp) (product)

[Get an implementation brief](/learn/workspace?topic=whatsapp)
