> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ycloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WhatsApp Messages API 最佳实践

> 构建适用于生产环境的可靠、合规且可观测的 WhatsApp 消息发送工作流。

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

## 准备工作

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

## 选择发送端点

默认使用队列端点。仅当应用程序在继续执行前必须确认 WhatsApp 是否已接受提交时，才使用直接发送端点。

| 端点 | 适用场景 | 运行效果 |
| - | - | - |
| `POST /whatsapp/messages` | 发送通知、营销活动或其他常规出站流量。 | YCloud 接受请求并异步提交。您的应用程序可以通过自身队列平抑流量峰值。 |
| `POST /whatsapp/messages/sendDirectly` | 发送 OTP 或其他需要同步提交的时效性消息。 | 请求会等待提交至 WhatsApp Business API，但不会等待最终投递结果。 |

任一端点返回的成功响应均不代表最终投递成功。请存储返回的消息 `id`，并使用 `whatsapp.message.updated` 事件来了解消息是处于 `sent`、`failed`、`delivered` 还是 `read` 状态。

<Warning>
  请勿将整个高吞吐量业务切换到 `sendDirectly` 来降低队列
  延迟。同步调用会占用应用程序资源，并且仍然需要
  异步处理状态。
</Warning>

## 创建内部发送记录

在调用 API 之前创建一条持久化记录。为该记录指定唯一的业务键（如订单事件 ID 加上消息用途）。在数据库中强制实施唯一性约束，以防止并发工作进程对同一业务事件重复发送。

至少记录以下内容：

| 字段 | 用途 |
| - | - |
| 业务键 | 防止两个工作进程为同一个业务事件创建多次尝试。 |
| `externalId` | 将 YCloud 数据与内部记录及对账报表相关联。 |
| YCloud `id` | 用于检索消息并匹配状态事件。 |
| `wamid` | 提交后（获取到该值时）用于与 WhatsApp 进行关联。 |
| 端点和尝试次数 | 说明消息的提交方式以及进行了多少次传输尝试。 |
| 当前状态和时间戳 | 构建当前运行视图，同时保留事件历史记录。 |

使用不包含消息内容或个人数据的不透明 `externalId`。API 建议传入唯一值，但 `externalId` 仅作为参考字段。它不是服务端的幂等键，不能使重复的 `POST` 请求保持安全幂等。

## 将响应与状态 Webhook 关联

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

### 1. 发送消息

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/messages \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "from": "+16315551111",
    "to": "+16315552222",
    "type": "template",
    "externalId": "order-ready-10001",
    "filterUnsubscribed": true,
    "filterBlocked": true,
    "template": {
      "name": "orders_pickup_ready_v2",
      "language": {
        "code": "en_US",
        "policy": "deterministic"
      }
    }
  }'
```

### 2. 存储已接受的响应

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "MESSAGE_ID",
  "wabaId": "WHATSAPP_BUSINESS_ACCOUNT_ID",
  "from": "+16315551111",
  "to": "+16315552222",
  "type": "template",
  "status": "accepted",
  "externalId": "order-ready-10001",
  "createTime": "2026-08-27T09:00:00.000Z"
}
```

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

### 3. 应用后续状态事件

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_MESSAGE_STATUS_1",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2026-08-27T09:00:02.000Z",
  "whatsappMessage": {
    "id": "MESSAGE_ID",
    "wamid": "wamid.BgNODYxN...",
    "status": "sent",
    "externalId": "order-ready-10001",
    "sendTime": "2026-08-27T09:00:01.000Z"
  }
}
```

通过 `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}`。

不要将状态模型实现为仅接受更高级别状态的规则。实际的送达更新并不总是按此顺序到达。请保留事件历史记录，并使对账机制能够更正当前视图。

## 重试时不产生重复发送

在重试前对失败进行分类。

| 失败类型 | 建议操作 |
| - | - |
| `400`、`404` 或 `422` | 修复请求、资源、模板或业务规则。不要原封不动地重试请求。 |
| `401` 或 `403` | 修复身份验证或账户访问权限。不要在未更改凭据的情况下重试。 |
| `429` | 降低并发量并在延迟后重试。 |
| `5xx` | 使用指数退避、抖动和最大尝试次数来重试临时失败。 |
| 超时或连接断开 | 将结果视为不明确。每当请求可能已到达 YCloud 时，在创建另一次发送前先进行对账。 |

安全的应用程序策略可以从少量重试、指数延迟、完全抖动和最大耗时限制开始。这些属于应用程序控制，而非 API 保证。将耗尽尝试次数的任务发送到审查队列，而不是无休止地重试。

在每次重试之前：

* 锁定或原子性地认领内部业务主键。
* 检查该记录是否已拥有 YCloud `id` 或状态事件。
* 不要使用新的 `externalId` 来掩盖早期不明确的尝试。
* 在达到配置的尝试次数或时长限制后停止。
* 在重放不明确的发送前，需要操作员明确执行操作。

## 选择模板和会话消息

在主动发起商业消息或在 24 小时客户服务窗口期外发送时，请使用已获批的模板。根据用户接收消息的原因选择消息模板类别，并在应用程序配置中维护其名称、语言和变量约束。

仅在客户服务窗口期处于开启状态且允许该内容类型时，才发送文本、媒体、互动、位置、联系人或心情回应消息。请根据客户最近发送的消息来确定窗口期。不要通过自己最后发送的出站消息来推断窗口期是否开启。

有关模板版本控制、审批关卡、语言区域和回滚的信息，请参阅 [管理 WhatsApp 模板](/zh/api-reference/guides/whatsapp-platform/manage-whatsapp-templates)。

## 高效处理媒体

* 在上传前验证文件支持的 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 签名、事件去重、快速确认响应及重放机制均已通过测试。
* [ ] 配置了定时拉取任务以对账延迟或丢失的事件。
* [ ] 可重试和不可重试的失败均具有受限的处理路径。
* [ ] 发送前严格执行模板规则与会话窗口规则。
* [ ] 媒体上传经过校验、复用、过期管理并能安全清理。
* [ ] 同意记录、退订、阻止列表、保留策略与日志记录管控均已核实。
* [ ] 批处理队列具备并发限制、背压机制、监控面板与告警设置。
* [ ] 运维人员可以暂停发送并审核状态不确定的尝试，而不会自动重放它们。

<CardGroup cols={2}>
  <Card title="发送 WhatsApp 消息" icon="whatsapp" href="/zh/api-reference/guides/whatsapp-platform/send-whatsapp-message">
    查看请求类型、字段、示例以及响应数据。
  </Card>

  <Card title="配置 Webhook" icon="webhook" href="/zh/api-reference/guides/api-fundamentals/configure-webhooks">
    验证签名并安全处理重复的事件推送。
  </Card>

  <Card title="上传 WhatsApp 媒体文件" icon="upload" href="/zh/api-reference/guides/whatsapp-platform/upload-whatsapp-media">
    上传受支持的媒体文件并复用返回的媒体 ID。
  </Card>

  <Card title="处理 API 错误" icon="triangle-exclamation" href="/zh/api-reference/guides/api-fundamentals/handle-errors">
    解析错误响应并应用有上限的重试策略。
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.