# 从 v1 迁移

import { Badge } from '@astrojs/starlight/components';

本指南将每个旧版 `/create*Message` 字段映射到其等效的 Messaging API v2 字段。在移植现有集成时，请以此为参考。

<Aside type="note">
旧版 v1 方法已被弃用，但仍可完全运行。没有硬性的停用日期，因此您可以按照自己的节奏进行迁移。对于新的集成，请使用 Messaging API v2。
</Aside>

## 高层级差异

| 方面 | v1 | v2 |
|---|---|---|
| 每个渠道的端点 | 每个渠道使用单独的方法 (`/createMessage`、`/createEmailMessage`、`/createSMSMessage`、`/createKakaoMessage` 等) | 单一端点 — `POST /messaging/v2/notify` |
| 身份验证 | 请求正文中的 `auth` 字段 | `Authorization: Token <API_TOKEN>` 标头 |
| 目标定位 | 混合：在同一请求中使用 `filter` + `conditions` + `devices` + `users` | 明确拆分：`NotifySegment` 与 `NotifyTransactional` |
| 内容 | 扁平化的 `content` + 同级的平台块 | 嵌套的 `payload.content.localized_content.{locale}.{platform}` |
| 响应 | `MessageCode[]` | `message_code` + 可选的 `unknown_identifiers` |

## 从 `/createMessage`

v1 `notifications[*]` 条目会变成单独的 `Notify` 请求（每个请求一条消息）。如果一个 v1 调用有多个条目，则为每个条目发出一个 `Notify` 请求。

**目标定位决策。** 如果 v1 条目使用 `devices` 或 `users`（显式列表），则将其映射到 `transactional`。否则，将其映射到 `segment`。

### 请求级字段

- `application` → `segment.application` 或 `transactional.application`（相同的 app-code 格式）。
- `applications_group`：v2 中不支持。请使用多个针对每个应用的请求。
- `auth`：已移至 `Authorization` 标头，不再位于请求正文中。

### 调度

- `send_date` (`"YYYY-MM-DD HH:mm"` 或 `"now"`) → `schedule.at` (RFC 3339 UTC 时间戳)。要重现 v1 的 `"now"`，请将 `schedule.at` 设置为当前时间。任何过去的时间戳都会立即发送。
- `ignore_user_timezone` → `schedule.follow_user_timezone`。**反转：**`ignore_user_timezone: true` 变为 `follow_user_timezone: false`。
- `timezone`：不支持。v2 始终对 `at` 使用 UTC。请在客户端进行转换。

### 目标定位

- `filter` (segment 名称) → `segment.code`。
- `conditions` (`[[tag, op, value], ...]`) → `segment.expression`。重写为 [seglang](/zh/developer/api-reference/segmentation-filters-api/segmentation-language/) 表达式。在 seglang 中，`*` 是逻辑与 (AND)，特定于应用的标签被引用为 `Tag("<application-code>", "<tag>", <op>, <value>)`。示例：`[["Country","EQ","BR"],["Language","EQ","pt"]]` 配合 `conditions_operator: AND` → `Tag("XXXXX-XXXXX", "Country", EQ, "br") * Tag("XXXXX-XXXXX", "Language", EQ, "pt")`。
- `conditions_operator` (`AND` / `OR`)：合并到 `segment.expression` 中。
- `devices` (hwid 或 push token) → `transactional.hwids.list` 或 `transactional.push_tokens.list`。v2 将两者分开：hwid 进入 `hwids`，原始 push token 进入 `push_tokens`。
- `users` → `transactional.users.list`。
- `platforms` (数字代码 `[1, 3, …]`) → `segment.platforms` 或 `transactional.platforms` (字符串枚举 `["IOS", "ANDROID", …]`)。请参阅 [Platform 枚举](/zh/developer/api-reference/messaging-api-v2/notify/#platform-enum)。

### 内容

- `content` (字符串) → `payload.content.localized_content.default.{platform}.body`。在 v2 中，内容始终是按区域设置和按平台划分的。将纯 v1 字符串放在特殊的 `"default"` 键下（包罗万象的翻译，请参阅[设备的区域设置选择](/zh/developer/api-reference/messaging-api-v2/payload-reference/#locale-selection-for-a-device)）。
- `content` (`{locale: text}`) → `payload.content.localized_content.{locale}.{platform}.body`。将正文复制到每个目标平台块中。
- `preset` → `payload.preset`。
- `data` → `payload.custom_data`。
- `rich_media` → `payload.open_action.rich_media.code`。
- `link` → `payload.open_action.link.url`。
- `minimize_link` (`0` 或 `2`) → `payload.open_action.link.shortener` (`NONE` 或 `BITLY`)。
- `inbox_image` → `payload.content.localized_content.{locale}.{platform}.inbox.image_url`（每个平台块都有自己的 `inbox`）。
- `inbox_date` → `payload.content.localized_content.{locale}.{platform}.inbox.expiration_date`。
- `inbox_days`：不支持。在客户端转换为绝对的 `expiration_date`。

### 交付控制

- `dynamic_content` / `dynamic_content_placeholders` → `segment` 或 `transactional` 上的 `dynamic_content_placeholders`。
- `campaign` → `segment` 或 `transactional` 上的 `campaign`。
- `capping_days` → `frequency_capping.days`。
- `capping_count` → `frequency_capping.count`。
- `send_rate` (int) → `send_rate.value` 配合 `send_rate.bucket: "1s"`。
- `message_type` (`"marketing"` / `"transactional"`) → `message_type` (`MESSAGE_TYPE_MARKETING` / `MESSAGE_TYPE_TRANSACTIONAL`)。

### v2 中不支持

- `transactionId`：没有直接的等效项。请在您这边跟踪关联性。
- `template_bindings`：Liquid 模板绑定在 v2 中不可用。如果您依赖它们，请继续使用 v1。

### 特定于平台的块

v1 在每个 `notifications[*]` 条目的顶层接受特定于平台的参数（`ios`、`android`、`safari`、`chrome` 等）。在 v2 中，它们被移到区域设置内部：

```
// v1
"notifications": [{
  "content": "Hello",
  "ios":     { "title": "Hi",    "sound": "default.caf" },
  "android": { "header": "Hi",   "led": "#ff0000" }
}]

// v2
"payload": {
  "content": {
    "localized_content": {
      "en": {
        "ios":     { "title": "Hi", "body": "Hello", "sound": "default.caf" },
        "android": { "title": "Hi", "body": "Hello", "led_color": "#ff0000" }
      }
    }
  }
}
```

平台块内的字段名称在某些地方有所不同。有关确切的 v2 名称，请参阅[Payload 参考](/zh/developer/api-reference/messaging-api-v2/payload-reference/)。

### 示例：前后对比

**v1 `/createMessage`**（推送到一个 segment）：

```json
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth":        "YOUR_API_TOKEN",
    "notifications": [{
      "send_date":  "2026-05-01 12:00",
      "content":    "Hello!",
      "platforms":  [1, 3],
      "filter":     "active_users",
      "campaign":   "YYYYY-YYYYY",
      "capping_days":  7,
      "capping_count": 3,
      "message_type":  "marketing"
    }]
  }
}
```

**v2 `/messaging/v2/notify`**：

```json
{
  "segment": {
    "application": "XXXXX-XXXXX",
    "platforms":   ["IOS", "ANDROID"],
    "code":        "active_users",
    "payload": {
      "content": {
        "localized_content": {
          "en": {
            "ios":     { "body": "Hello!" },
            "android": { "body": "Hello!" }
          }
        }
      }
    },
    "schedule":          { "at": "2026-05-01T12:00:00Z" },
    "frequency_capping": { "days": 7, "count": 3 },
    "campaign":          "YYYYY-YYYYY",
    "message_type":      "MESSAGE_TYPE_MARKETING"
  }
}
```

## 从 `/createTargetedMessage`

`/createTargetedMessage` 在大多数情况下映射到 `transactional`，或者如果您纯粹将其用作没有显式标识符的跨应用 `devices_filter`，则映射到 `segment`。

- `devices_filter` → `segment.expression` (seglang) 或 `segment.filter_expression` (结构化)。
- `content` → `payload.content.localized_content.{locale}.{platform}.body`。
- 所有其他字段，与上面的 `/createMessage` 相同。

## 从 `/createEmailMessage`

迁移到 `Notify`，使用 `platforms: ["EMAIL"]` 和一个 `email_payload` 块。完整参考：[Email payload 参考](/zh/developer/api-reference/messaging-api-v2/email-payload-reference/)。

- `subject` → `email_payload.subject`（按区域设置键控的映射。将单区域设置值包装在 `{"en": "..."}` 中）。
- `content` (HTML) → `email_payload.body`。
- `email_template` → `email_payload.email_template`。
- `from` / `from_name` → `email_payload.from` (`{ "name": "...", "email": "..." }`)。
- `reply_to` / `reply_to_name` → `email_payload.reply_to`。
- `list_unsubscribe` → `email_payload.list_unsubscribe`。
- `attachments` → `email_payload.attachments` (`[{ "name": "...", "content": "<base64>" }]`)。
- 目标定位、调度、活动等，与 `/createMessage` 相同。

## 从 `/createSMSMessage`

迁移到 `Notify`，使用 `platforms: ["SMS"]`。SMS 正文通过应用配置的 SMS 提供商发送。将内容放在任何已填充平台块的 `payload.content.localized_content.{locale}.{platform}.body` 中。

特定于 SMS 的提供商选项（发件人 ID 等）继续来自应用的 SMS 配置，而不是请求正文。

## 从 `/createKakaoMessage`

迁移到 `Notify`，使用 `platforms: ["KAKAO"]`，并使用 `payload.content.localized_content.{locale}.kakao`：

- `template_id` → `kakao.template`。
- `content` → `kakao.content`。
- `variables` → `kakao.content_variables`（JSON 字符串化）。

## 从 `/createWhatsAppMessage`

迁移到 `Notify`，使用 `platforms: ["WHATS_APP"]`，并使用 `payload.content.localized_content.{locale}.whatsapp`：

- `content` (自由格式文本) → `whatsapp.content`。仅在 24 小时客户服务窗口内由 Meta 发送。
- `content_id` → `whatsapp.content_id`。预先批准的 Meta 模板的名称。
- `language` → `whatsapp.language`。Meta 模板区域设置（例如 `"en_US"`）。独立于外部的 `LocalizedContent` 区域设置键。
- `content_variables` (v1 中的对象) → `whatsapp.content_variables` (JSON 字符串化的对象)。示例 v1 `{"1": "John"}` 变为 v2 `"{\"1\":\"John\"}"`。
- `button_url_variables` (对象) → `whatsapp.button_url_variables` (JSON 字符串化)。
- `header_variables` (对象) → `whatsapp.header_variables` (JSON 字符串化)。
- `preset` → `payload.preset` (payload 级别的通用预设)。
- 目标定位：在 v1 中进入 `devices` 的 WhatsApp 电话号码（例如 `"whatsapp:+1234567890"`）必须通过 [`/registerDevice`](/zh/developer/api-reference/device-api#registerdevice) 针对用户进行注册。在 v2 中，使用 `transactional.users.list`（或通过 `transactional.hwids.list` 使用 hwid）来定位结果用户。
- `use_auto_registration`：不支持。在发送前注册 WhatsApp 号码。

## 从 `/createLineMessage`

迁移到 `Notify`，使用 `platforms: ["LINE"]`，并使用 `payload.content.localized_content.{locale}.line`：

- `content` (纯文本) → `line.content`。
- `preset` (LINE 预设代码) → `line.template`。v2 字段存储一个引用在 Pushwoosh Control Panel 中配置的 LINE 模板的代码。
- 内联 `template` (v1 图像、轮播或 flex 消息结构)：v2 不直接支持。在 Control Panel 中将富媒体消息预先配置为 LINE 预设，并通过 `line.template` 引用它。
- 目标定位：v1 `devices` 列表（通过 SDK / `/registerDevice` 注册的 LINE 用户 ID）在 v2 中变为 `transactional.users.list`（或通过 `transactional.hwids.list` 使用 hwid）。

## 响应差异

v1 `/createMessage` 返回：

```json
{
  "status_code": 200,
  "status_message": "OK",
  "response": { "Messages": ["XXXXX-XXXXX-AAAAA"] }
}
```

v2 `Notify` 返回：

```json
{
  "result": {
    "message_code": "XXXXX-XXXXX-AAAAA",
    "unknown_identifiers": []
  }
}
```

非 200 响应遵循标准的 gRPC-Gateway 错误封装 (`{ "code": ..., "message": ..., "details": [...] }`)，而不是 v1 的 `status_code` / `status_message` 对。