Sign inGet started

WhatsApp 互动消息

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

六种类型

类型Bird interactive.type头部底部正文上限
回复按钮button文本、图片、视频、文档1024
列表菜单list仅文本4096
链接按钮cta_url文本、图片、视频、文档1024
媒体轮播carousel消息无头部;每张卡片可含图片或视频消息 1024,每张卡片 160
位置请求location_request_message1024
联系方式请求request_contact_info1024
所有类型均为自由格式:只能在开放的客服窗口内发送,Meta 不会像审核模板那样对其进行审核。
互动消息属于自由格式内容,因此受客服窗口规则约束:参阅客服窗口了解其含义以及窗口关闭时的返回结果。
每次互动发送还需要 from,即你的工作区拥有的号码。Bird 的托管号码无法用于此目的,因此互动发送需要先接入一个你自己的号码。

互动内容字段

interactivePOST /v1/whatsapp/messages 上互斥的内容字段之一,与 templatetextimage 等并列:一次发送中只能存在其中之一。在 interactive 内部,type 指明这是六种变体中的哪一种,该变体自身的字段承载其余数据(buttonslistcta_urlcards)。Schema 禁止出现其他变体的字段,因此在一次发送中混用两种变体会在到达处理器之前就验证失败。
关于请求信封、202 响应模型和安全重试,请参阅发送 WhatsApp 消息,本页不再重复介绍。
以下是一条最简互动消息:在一次回复按钮发送中放置两个 WhatsApp 按钮,每次一种语言。
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);

按钮

六种类型中有四种包含按钮,它们都使用相同的结构:一个带判别字段的对象,其 typequick_replycta_url,各自携带同名的嵌套字段。quick_reply 按钮携带 slugtextcta_url 按钮携带 texturl。各类型接受的按钮形式如下:
  • 回复按钮仅发送 quick_reply 按钮,1 到 3 个。
  • 链接按钮只发送一个 cta_url 按钮。
  • 媒体轮播在每张卡片上放置按钮:一个 cta_url 按钮,或最多三个 quick_reply 按钮,且轮播中每张卡片必须一致。
  • 列表菜单使用分区内的行而非此按钮对象,详见其专属页面。
quick_reply 按钮的 slug 是你为该按钮设置的标识。它不会展示给收件人,收件人看到的只有它的 text 标签,而 slug 会在回复中原样回传。正是这个往返过程使回复可以关联到产生它的按钮,因此在这里统一说明一次,而不在每个子页面重复。

读取回复

点击按钮或选择菜单行会发送一条入站消息,携带一个 interactive_reply 对象。interactive_reply.typebuttonlist;无论是哪个,嵌套对象都携带你声明的 slugtext(即收件人实际看到的已点击标签)。两种请求类型(位置请求和联系方式请求)的回复方式不同:位置请求的回复是一条普通的入站位置消息,联系方式请求的回复是一条入站联系人名片,而非 interactive_reply
回复通过消息列表和 GET /v1/whatsapp/messages/{id} 到达你,与任何入站 WhatsApp 消息的方式相同。要在回复到达时立即处理而非轮询,请订阅 whatsapp.received webhook:其载荷携带 interactive_reply,因此已包含被点击的按钮或行。接收互动回复介绍了点击的读取结构、webhook 载荷以及到达其他字段的点击。

引用消息以关联回复

发送时的 in_reply_to_message_id 引用同一会话中的一条早期消息,每条消息(无论发送还是接收)在读取时都会回传该字段。它是双向共用的同一个字段。
此关联是非对称的。点击 WhatsApp 按钮或菜单行时会携带 Meta 自有的 context,因此 in_reply_to_message_id 可解析到提供该选项的消息。共享的联系人名片不携带 context,因此无法解析:你需要通过 from 和时间来关联联系方式请求的回复,而非依赖此字段。
解析通过消息上下文存储进行,未命中时会省略该字段而非返回一个值。这在传输层上与完全没有回复目标的回复无法区分。如果集成需要可靠的关联,不应仅依赖此字段:在发送时携带你自己的 metadata,然后基于它进行匹配。
消息可被引用的窗口限制为 15 天;超过后发送会返回 404 E15071,因为 Bird 不再持有引用所需的提供方 ID。发送 WhatsApp 消息负责发送端字段的说明:其长度、解析方式和请求结构。

错误

三个错误码专用于互动内容。每个仅在包含其所检查字段的类型上触发,因此第四列标明了哪些类型会实际遇到该错误。
错误码状态触发条件适用于
E15055 WhatsAppInteractiveLimitExceeded422消息超出其类型的限制;目前为列表各分区合计超过 10 行。仅列表菜单
E15056 WhatsAppInteractiveDuplicateLabel422同一消息中两个按钮或行使用了相同的标签。任何包含带标签按钮或行的类型:回复按钮、列表菜单、媒体轮播
E15059 WhatsAppInteractiveCarouselButtonsMismatch422轮播中的卡片未全部携带相同的按钮。仅媒体轮播
每次互动发送也可能遇到任何 WhatsApp 发送都会遇到的错误:客服窗口已关闭、发送方缺失或无效、收件人无效或内容不明确。这些错误在所有 WhatsApp 内容类型中通用,并非互动消息特有;参阅发送 WhatsApp 消息获取完整列表,此处不再重复。

后续步骤