Skip to main content
利用这些最佳实践在生产规模下可靠地发送 WhatsApp 消息。您将了解如何选择正确的端点、关联每次尝试、收敛投递状态、安全重试、落实用户许可并控制吞吐量。

准备工作

  • 连接并注册用于发送消息的 WhatsApp 商业电话号码。
  • 在服务器端妥善保存您的 YCloud API Key。
  • 为 whatsapp.message.updated 配置带签名的 Webhook 端点。
  • 定义系统如何记录用户许可、退订请求、消息用途以及数据留存策略。
  • 指定消息发送、Webhook 处理及突发事件响应的负责人。

选择发送端点

默认使用队列端点。仅当应用程序在继续执行前必须确认 WhatsApp 是否已接受提交时,才使用直接发送端点。 任一端点返回的成功响应均不代表最终投递成功。请存储返回的消息 id,并使用 whatsapp.message.updated 事件来了解消息是处于 sent、failed、delivered 还是 read 状态。
请勿将整个高吞吐量业务切换到 sendDirectly 来降低队列 延迟。同步调用会占用应用程序资源,并且仍然需要 异步处理状态。

创建内部发送记录

在调用 API 之前创建一条持久化记录。为该记录指定唯一的业务键(如订单事件 ID 加上消息用途)。在数据库中强制实施唯一性约束,以防止并发工作进程对同一业务事件重复发送。 至少记录以下内容: 使用不包含消息内容或个人数据的不透明 externalId。API 建议传入唯一值,但 externalId 仅作为参考字段。它不是服务端的幂等键,不能使重复的 POST 请求保持安全幂等。

将响应与状态 Webhook 关联

以下示例在整个发送工作流中使用相同的标识符。

1. 发送消息

2. 存储已接受的响应

将 MESSAGE_ID、accepted 和响应时间保存到已有的内部记录中。切勿直接将业务通知标记为已送达。

3. 应用后续状态事件

通过 whatsappMessage.id 匹配事件。使用 externalId 进行业务对账,使用 wamid 进行服务商排查。

构建收敛状态模型

常见的流转过程为 accepted → sent → delivered → read。failed 可能在 sent 更新之前或之后发生。Webhook 可能会重复、延迟或乱序送达。read 更新也可能在没有单独 delivered 事件的情况下到达。 按以下方式处理每个事件:
  1. 使用原始请求体验证 Webhook 签名。
  2. 持久化存储事件,使用事件 id 作为去重键。
  3. 及时返回 2xx 响应,然后异步处理事件。
  4. 将 whatsappMessage.id 与内部发送记录进行匹配。
  5. 存储事件状态及其可用的消息时间戳。保留审计所需的原始事件元数据,但移除不必要的消息内容。
  6. 更新当前业务视图,且不丢弃冲突或后续的凭证。即使没有收到单独的 delivered 事件,也将 read 视为消息已投递的证据。
  7. 当事件冲突、终态超出服务目标仍未达到或 Webhook 管道不可用时,检索 GET /whatsapp/messages/{id}。
不要将状态模型实现为仅接受更高级别状态的规则。实际的送达更新并不总是按此顺序到达。请保留事件历史记录,并使对账机制能够更正当前视图。

重试时不产生重复发送

在重试前对失败进行分类。 安全的应用程序策略可以从少量重试、指数延迟、完全抖动和最大耗时限制开始。这些属于应用程序控制,而非 API 保证。将耗尽尝试次数的任务发送到审查队列,而不是无休止地重试。 在每次重试之前:
  • 锁定或原子性地认领内部业务主键。
  • 检查该记录是否已拥有 YCloud id 或状态事件。
  • 不要使用新的 externalId 来掩盖早期不明确的尝试。
  • 在达到配置的尝试次数或时长限制后停止。
  • 在重放不明确的发送前,需要操作员明确执行操作。

选择模板和会话消息

在主动发起商业消息或在 24 小时客户服务窗口期外发送时,请使用已获批的模板。根据用户接收消息的原因选择消息模板类别,并在应用程序配置中维护其名称、语言和变量约束。 仅在客户服务窗口期处于开启状态且允许该内容类型时,才发送文本、媒体、互动、位置、联系人或心情回应消息。请根据客户最近发送的消息来确定窗口期。不要通过自己最后发送的出站消息来推断窗口期是否开启。 有关模板版本控制、审批关卡、语言区域和回滚的信息,请参阅 管理 WhatsApp 模板。

高效处理媒体

  • 在上传前验证文件支持的 MIME 类型和大小。对于超大或不受支持的文件, 请勿在未做更改的情况下重试。
  • 使用将要发送消息的商业电话号码进行上传。
  • 在返回的媒体 ID 有效期内,重复发送同一已获批素材时可复用该 媒体 ID。上传的媒体文件将保留 30 天。
  • 存储素材校验和、MIME 类型、媒体 ID、发送者和过期时间, 以避免工作节点为每个收件人重复上传相同文件。
  • 过期后或发送者上下文发生变更时重新上传。
  • 当消息结构要求提供链接时(包括互动消息标头中的媒体), 请改用公开 URL。
  • 从存储流式传输大文件上传,设置请求超时,并在使用后删除 本地临时文件。

执行授权许可并最小化数据

在发送前记录许可来源、目的、时间和允许的渠道。在营销活动、政策要求的事务性工作流、重试以及手动重放中应用最新的有效退订状态。 对于 POST /whatsapp/messages,当工作流必须强制执行 YCloud 抑制列表时,请设置 filterUnsubscribed: true 和 filterBlocked: true。这些字段默认为 false。它们不适用于 sendDirectly,因此直接发送工作流必须在调用 API 之前检查抑制列表。 抑制过滤器是最终的安全检查,不能替代许可。仅存储所述目的所需的标识符和送达元数据。不要在常规应用程序日志中记录 API 密钥、模板变量、消息正文和电话号码。对消息和 Webhook 记录实施保留和访问控制。

控制批量吞吐量

将批量任务放入有界队列中,并通过固定的工作节点池进行发送。按账户和商业电话号码分别跟踪并发量,避免单个发送者或租户占满所有工作节点。 当以下任一信号增加时,应用背压:
  • 429 响应
  • 请求延迟和超时
  • 5xx 响应
  • 队列堆积时长或重试积压
  • Webhook 延迟和未解决的 accepted 消息
当 YCloud 或下游送达变慢时降低并发量。恢复后逐步增加。重试失败消息的速率不要超过最初的发送速率。 至少监控请求量、接受率、按 HTTP 状态和错误代码划分的错误率、送达状态率、从 accepted 到后续各状态的时间、队列深度、最老队列时长、重试次数、Webhook 延迟、去重次数和对账偏差。针对偏离正常基线的持续变化发出告警,而不是针对单条失败消息。

常见反模式

  • 当 API 返回 accepted 时即标记消息已送达。
  • 将 externalId 视为 YCloud 幂等性密钥。
  • 对所有非 2xx 响应或超时进行无限制重试。
  • 对所有流量均使用 sendDirectly。
  • 假定 Webhook 具有唯一性、有序性或完整性。
  • 在客户服务窗口期外发送自由格式消息。
  • 为每个接收者重复上传相同的媒体文件。
  • 仅依赖抑制过滤器而未记录用户同意信息。
  • 记录 API 密钥、完整负载或不必要的个人数据。
  • 以无限制并发且缺乏背压控制的方式启动批处理。

上线前检查清单

  • 终端节点的选择符合工作负载和延迟要求。
  • 数据库唯一性规则保护了内部业务键。
  • externalId、YCloud id 以及 wamid 各自具有明确记录的职责。
  • 在收到状态凭证之前,初始响应保持为非最终状态。
  • Webhook 签名、事件去重、快速确认响应及重放机制均已通过测试。
  • 配置了定时拉取任务以对账延迟或丢失的事件。
  • 可重试和不可重试的失败均具有受限的处理路径。
  • 发送前严格执行模板规则与会话窗口规则。
  • 媒体上传经过校验、复用、过期管理并能安全清理。
  • 同意记录、退订、阻止列表、保留策略与日志记录管控均已核实。
  • 批处理队列具备并发限制、背压机制、监控面板与告警设置。
  • 运维人员可以暂停发送并审核状态不确定的尝试,而不会自动重放它们。

发送 WhatsApp 消息

查看请求类型、字段、示例以及响应数据。

配置 Webhook

验证签名并安全处理重复的事件推送。

上传 WhatsApp 媒体文件

上传受支持的媒体文件并复用返回的媒体 ID。

处理 API 错误

解析错误响应并应用有上限的重试策略。