> ## 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 消息状态更新 Webhook 示例

> 了解已发送、已送达、已读和失败的 WhatsApp 消息更新。

<Note>有关基于 schema 生成的完整目录，请参阅[所有示例](/zh/api-reference/guides/examples/webhook-examples/webhook-payload-examples)。</Note>

## 概述

了解已发送、已送达、已读和失败的 WhatsApp 消息更新。

## 开始之前

* 在您的应用程序中创建一个公开的 HTTPS 端点。
* 为您需要的事件类型配置 YCloud Webhook 端点。
* 安全存储端点签名密钥。
* 确保事件处理具有幂等性。

## 工作原理

事件发生时，YCloud 会发送 HTTP `POST` 请求。验证签名，持久化记录该事件，返回 `2xx` 响应，并异步处理耗时工作。

## 请求

以下场景展示了发送到您的 Webhook URL 的请求。将事件 `id` 作为交付标识符，并使用 `type` 路由有效载荷。

## 响应

接收事件后返回 `2xx` 状态。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
HTTP/1.1 200 OK
```

<Note>有关端点设置、签名验证和重试行为，请参阅[配置 Webhook](/zh/api-reference/guides/api-fundamentals/configure-webhooks)。</Note>

成功请求 API 发送消息后，消息的状态为 `accepted`。消息状态更新将触发 `whatsapp.message.updated` Webhook。

通常情况下，消息状态：

* 如果我们无法投递此消息，状态将变更为 `failed`。
* 如果可以投递此消息，状态将变更为 `sent`，随后可能会变更为 `failed`、`delivered` 或 `read`。
* 如果此消息已送达收件人的设备，状态将变更为 `delivered` 或 `read`。

但实际情况较为复杂。首先，我们不保证 Webhook 是按顺序通知的，特别是当事件几乎同时发生时。其次，`delivered` 事件可能会发生在 `failed` 之后，反之亦然，尤其是当最终用户使用多个设备时。

## 消息已发送

在这种情况下，您的 Webhook 端点收到了消息 `sent` 事件：

* 消息 `status` 为 `sent`，表示消息正在 WhatsApp 的系统中传输。
* 包含会话信息，包括会话过期时间和来源类型。
* 包含我们可能会向您收取的 **预估** `pricingCategory` 和 `totalPrice`。
* 包含 `wamid`，即 WhatsApp 平台上的原始消息 ID，以 `wamid.` 开头。

### 请求

```shell theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl 'https://YOUR-WEBHOOK-ENDPOINT-URL' \
-H 'Content-Type: application/json' \
-d '{
  "id": "evt_eEVCy8eNqD9EvcFI",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2023-02-22T12:00:00.000Z",
  "whatsappMessage": {
    "id": "63f5d602367ea403f8175a6c",
    "wamid": "wamid.BgNODYxN...",
    "recipientUserId" : "US.13491208655302741918",
    "parentRecipientUserId": "US.ENT.11815799212886844830",
    "customerProfile": {
      "name": "Pablo M."
    },
    "status": "sent",
    "pricingCategory": "marketing",
    "totalPrice": 0.0,
    "currency": "USD",
    "createTime": "2022-03-01T12:00:00.000Z",
    "sendTime": "2022-03-01T12:00:01.000Z",
    "bizType": "whatsapp",
    "type": "text",
    "text": {
      "body": "Hi there! How can we help?"
    },
    "externalId": "EXTERNAL-ID"
  }
}'
```

### 响应

持久化接收事件后确认交付。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
HTTP/1.1 200 OK
```

### 说明

* **`totalPrice` 仅为首条消息送达前的预估价格，当 `status` 变为 `delivered` 或 `read` 时，该价格即为最终价格。已发送但尚未送达的消息所占用的余额，在消息被丢弃（已发送但 30 天内未送达的消息会被丢弃）之前将无法使用。**

* 通常，状态为 `sent` 的消息很快会变更为 `delivered` 或 `read`，除非遇到以下情况：
  * 收件人的 WhatsApp 账户离线，您发送的 WhatsApp 消息将在收件人拥有正常或可用的网络连接后才会送达。
  * 发送给已拉黑您的联系人的任何消息将始终显示消息 `sent`，且永远不会变更为 `delivered`。
  * 收件人已关闭已读回执，您将不会收到消息 `read` 回执。
  * 消息随后变更为 `failed`，错误码为 `131026`，表示“消息无法投递”或“接收方无法接收此消息”。这通常是因为收件人未注册，或使用的是较旧的 WhatsApp 版本。
  * 为了提供高质量的用户体验，该消息未被投递。请参阅[单用户营销模板消息限制](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-message-templates#per-user-marketing-template-message-limits)。

## 消息已送达

在这种情况下，您的 Webhook 端点收到了消息 `delivered` 事件：

* 消息 `status` 为 `delivered`，表示消息已送达收件人的设备。

### 请求

```shell theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl 'https://YOUR-WEBHOOK-ENDPOINT-URL' \
-H 'Content-Type: application/json' \
-d '{
  "id": "evt_eEVCy8eNqD9EvcFI",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2023-02-22T12:00:00.000Z",
  "whatsappMessage": {
    "id": "63f5d602367ea403f8175a6c",
    "wamid": "wamid.BgNODYxN...",
    "recipientUserId" : "US.13491208655302741918",
    "parentRecipientUserId": "US.ENT.11815799212886844830",
    "customerProfile": {
      "name": "Pablo M.",
      "username": "@pablomorales"
    },
    "status": "delivered",
    "pricingModel": "PMP",
    "pricingType": "regular",
    "pricingCategory": "marketing",
    "totalPrice": 0.0,
    "currency": "USD",
    "createTime": "2022-03-01T12:00:00.000Z",
    "sendTime": "2022-03-01T12:00:01.000Z",
    "deliverTime": "2022-03-01T12:00:02.000Z",
    "bizType": "whatsapp",
    "type": "text",
    "text": {
      "body": "Hi there! How can we help?"
    },
    "externalId": "EXTERNAL-ID"
  }
}'
```

### 响应

持久化接收事件后确认交付。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
HTTP/1.1 200 OK
```

### 说明

* 此事件表明您的企业发送的消息已送达用户的设备。
* **状态要变为 `read`，前提必须是已经 `delivered`。在某些场景下，例如当用户正处于聊天界面且消息到达时，消息几乎同时处于 `delivered` 和 `read` 状态。在这些或类似场景中，将不会发送 `delivered` 通知，因为消息被阅读即意味着已被送达。这种机制是出于内部优化的考虑。**
* 我们可能会针对同一条消息生成超过 1 个 `delivered` Webhook 事件，尤其是当最终用户使用多个设备时。
* **pricingModel**："PMP"——表示适用按消息计费。另请参阅 [whatsapp-message-pricing-updates](https://docs.ycloud.com/reference/whatsapp-message-pricing-updates)
* **pricingType**
  * **regular** — 表示该消息计费。
  * **free\_customer\_service** — 表示该消息免费，因为它是在客服时间窗口内发送的效用消息模板或非模板消息。
  * **free\_entry\_point** — 表示该消息免费，因为它是免费切入点会话的一部分。

## 消息已读

在这种情况下，您的 Webhook 端点收到了消息 `read` 事件：

* 消息 `status` 为 `read`，表示接收者已阅读该消息。

### 请求

```shell theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl 'https://YOUR-WEBHOOK-ENDPOINT-URL' \
-H 'Content-Type: application/json' \
-d '{
  "id": "evt_eEVCy8eNqD9EvcFI",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2023-02-22T12:00:00.000Z",
  "whatsappMessage": {
    "id": "63f5d602367ea403f8175a6c",
    "wamid": "wamid.BgNODYxN...",
    "recipientUserId" : "US.13491208655302741918",
    "parentRecipientUserId": "US.ENT.11815799212886844830",
    "customerProfile": {
      "name": "Pablo M.",
      "username": "@pablomorales"
    },
    "status": "read",
    "pricingModel": "PMP",
    "pricingType": "regular",
    "pricingCategory": "marketing",
    "totalPrice": 0.0,
    "currency": "USD",
    "createTime": "2022-03-01T12:00:00.000Z",
    "sendTime": "2022-03-01T12:00:01.000Z",
    "deliverTime": "2022-03-01T12:00:02.000Z",
    "readTime": "2022-03-01T12:00:02.000Z",
    "bizType": "whatsapp",
    "type": "text",
    "text": {
      "body": "Hi there! How can we help?"
    },
    "externalId": "EXTERNAL-ID"
  }
}'
```

### 响应

在持久化接收事件后确认送达。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
HTTP/1.1 200 OK
```

### 说明

* 如果接收者关闭了已读回执，您将不会收到消息 `read` 回执。

## 消息失败

在这种情况下，您的 Webhook 端点收到了消息 `failed` 事件：

* 消息 `status` 为 `failed`。
* 包含 `errroCode`、`errorMessage` 和 `whatsappApiError`。

### 请求

```shell theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl 'https://YOUR-WEBHOOK-ENDPOINT-URL' \
-H 'Content-Type: application/json' \
-d '{
  "id": "evt_eEVCy8eNqD9EvcFI",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2023-02-22T12:00:00.000Z",
  "whatsappMessage": {
    "id": "63f5d602367ea403f8175a6c",
    "wamid": "wamid.BgNODYxN...",
    "recipientUserId" : "US.13491208655302741918",
    "parentRecipientUserId": "US.ENT.11815799212886844830",
    "status": "failed",
    "errorCode": "100",
    "errorMessage": "Parameter Invalid",
    "whatsappApiError": {
      "message": "(#100) Invalid parameter",
      "type": "OAuthException",
      "code": "100",
      "fbtrace_id": "AwmiSOCojlAkqvjCTjGt37r",
      "error_data": {
        "messaging_product": "whatsapp",
        "details": "Parameter Invalid"
      }
    },
    "pricingCategory": "marketing",
    "totalPrice": 0.0,
    "currency": "USD",
    "bizType": "whatsapp",
    "type": "text",
    "text": {
      "body": "Hi there! How can we help?"
    },
    "externalId": "EXTERNAL-ID"
  }
}'
```

### 响应

在持久化接收事件后确认送达。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
HTTP/1.1 200 OK
```

### 说明

* 这些事件旨在通知您先前向客户发送的出站消息的状态变化。
* 消息失败的原因通常是消息请求参数无效、客户手机号未注册等。有关错误处理，请参阅 [WhatsApp 错误](https://docs.ycloud.com/reference/whatsapp-errors)。
* 如果我们曾尝试将此消息提交给 Meta 的 WhatsApp 平台，则会提供 `whatsappApiError`，以帮助您了解错误详情。另请参阅 [Cloud API 错误代码](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes)。
* 我们不会对失败的消息向您收取费用。


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