WhatsApp 服务消息
服务消息是你发送的除预审批模板以外的任何内容:即企业在已开启的对话中发送的自由格式内容。POST /v1/whatsapp/messages 每条消息只能携带九种服务消息内容类型之一,或一个模板。本页介绍九种类型的共同特性;每种类型各自的页面介绍其传输格式和限制。
内容类型
| 类型 | 字段 | 携带内容 | 使用场景 |
|---|---|---|---|
| 纯文本 | text | 最多 4096 个字符的正文,可选链接预览 | 发送不带附件的消息 |
| 图片 | image | 一个公开的图片 URL 和可选的说明文字 | 发送照片或图形 |
| 视频 | video | 一个公开的视频 URL 和可选的说明文字 | 发送视频片段 |
| 音频 | audio | 一个公开的音频 URL,可选择以语音备忘录形式呈现 | 发送语音消息或音频片段 |
| 贴纸 | sticker | 一个公开的 WebP 图片 URL | 发送贴纸 |
| 文档 | document | 一个公开的文件 URL、可选的说明文字和可选的文件名 | 发送 PDF、电子表格或其他文件 |
| 位置 | location | 经纬度坐标,可选的名称和地址 | 发送地图标记,例如取件点 |
| 联系人名片 | contact_cards | 一到五张联系人名片,每张包含姓名以及任意数量的电话号码、电子邮件、网站或地址 | 分享某人的详细信息,例如同事的号码 |
| 互动消息 | interactive | 正文加上按钮、菜单、链接、卡片,或位置/联系人请求 | 希望收件人点击操作而非自由输入回复 |
一个请求只能携带 template 或这九个字段之一。既没有携带也没有选择其中任何一个,或携带了多个,请求会被拒绝并返回 422。
客服窗口
服务消息(即上述九种类型中的任何一种)只能在已开启的 24 小时客服窗口内投递。联系人向你的企业号码发送消息或拨打电话即可开启该窗口,此后他们每发送一条消息都会将窗口重置为 24 小时。
向已关闭的窗口发送服务消息会被立即拒绝:请求返回 422 E15044 WhatsAppServiceWindowClosed,不会创建消息也不会产生费用。请改为发送已审批的模板;模板不受窗口限制,可直接送达联系人,而对方的回复会重新开启窗口。如果窗口在接受和发送之间的瞬间关闭,消息仍然会失败,但以异步方式呈现:消息到达 failed,last_error 上显示 service_window_expired。
接受时的检查是尽力而为,不是保证:闸门按放行方向失效,因此存储未命中或读取错误会让发送通过而非阻止。因此 202 并不能证明发送时窗口处于开启状态;最终信号是消息自身的状态,而非接受响应。
每条服务消息还需要 from,即你的工作区拥有的一个号码。Bird 的托管号码不支持此功能,因此服务消息需要先接入你自己的号码;参见电话号码设置。
参见客服窗口了解完整生命周期:窗口如何开启、什么会重置它,以及如何追踪。
通过 URL 发送媒体
image、video、audio、sticker 和 document 都接受一个 url,指向 WhatsApp 在发送时抓取的文件,而不是你上传到 Bird 的文件。Bird 在接受时、入队之前会检查 URL 的格式:
- 非空且可解析,包含主机名且不含原始空格
- 协议为 https
http URL 在接受时会被拒绝并返回 422,尽管 WhatsApp 本身可以正常抓取。这是 Bird 的策略,而非 WhatsApp 施加的限制。
Bird 不检查文件大小、MIME 类型或 URL 是否可达。WhatsApp 在发送消息时自行抓取该 URL,因此签名 URL 需要在发送之后仍然有效,而不仅仅在你发出请求时有效;私有或过期的 URL 会在 WhatsApp 尝试抓取时失败。WhatsApp 还会缓存已抓取的 URL 约 10 分钟,因此在该时间窗口内重新发送相同的 URL 会复用首次抓取的结果,而非重新抓取。
媒体发送失败时
媒体发送遵循与任何 WhatsApp 消息相同的异步路径:Bird 返回 202 并接受消息,然后 WhatsApp 在发送时抓取 URL。如果抓取失败,消息到达 failed,last_error 上显示 media_rejected,其底层是 Meta 的 131053。
media_rejected 是一个涵盖性错误,包括文件过大、404、DNS 解析失败和 MIME 类型错误等情况;Bird 不会进一步细分,因此不要期望每种原因都有不同的错误码。
异步失败的媒体发送仍然会被计费。计费发生在 Bird 处理已接受的发送时,即 WhatsApp 抓取 URL 之前,一旦扣费完成就没有退款途径。请据此做好预算:在 media_rejected 中后续失败的消息与成功投递的消息费用相同。
读取联系人发送的内容
入站消息携带相同的九种类型之一,因此你读取的字段与联系人使用的类型一致。联系人名片无论是联系人分享的还是你发送的,都通过同一个 contact_cards 字段读取。接收 WhatsApp 消息介绍了如何通过 API 读取入站消息、抓取联系人发送的媒体,以及 whatsapp.received webhook。
后续步骤
- 发送 WhatsApp 消息:请求信封、202 模型和安全重试
- 互动消息:收件人可以点击的六种类型
- 接收 WhatsApp 消息:入站消息、媒体和 whatsapp.received webhook
- WhatsApp 模板:窗口关闭后仍可发送的消息