# การย้ายจาก v1

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

คู่มือนี้จะจับคู่ทุกฟิลด์ของ `/create*Message` แบบดั้งเดิมกับฟิลด์ที่เทียบเท่าใน Messaging API v2 ใช้เป็นข้อมูลอ้างอิงขณะย้ายการผสานรวมที่มีอยู่

<Aside type="note">
เมธอด v1 แบบดั้งเดิมถูกเลิกใช้งานแล้วแต่ยังคงทำงานได้อย่างสมบูรณ์ ยังไม่มีกำหนดการยุติการใช้งานที่แน่นอน ดังนั้นคุณสามารถย้ายข้อมูลได้ตามความสะดวก สำหรับการผสานรวมใหม่ ให้ใช้ Messaging API v2
</Aside>

## ความแตกต่างในระดับสูง

| แง่มุม | v1 | v2 |
|---|---|---|
| Endpoint ต่อช่องทาง | เมธอดแยกต่อช่องทาง (`/createMessage`, `/createEmailMessage`, `/createSMSMessage`, `/createKakaoMessage`, …) | endpoint เดียว — `POST /messaging/v2/notify` |
| Auth | ฟิลด์ `auth` ใน body ของ request | เฮดเดอร์ `Authorization: Token <API_TOKEN>` |
| การกำหนดเป้าหมาย | ผสม: `filter` + `conditions` + `devices` + `users` ใน request เดียวกัน | แบ่งชัดเจน: `NotifySegment` vs `NotifyTransactional` |
| เนื้อหา | `content` แบบแบน + บล็อกแพลตฟอร์มระดับเดียวกัน | `payload.content.localized_content.{locale}.{platform}` แบบซ้อน |
| Response | `MessageCode[]` | `message_code` + `unknown_identifiers` ที่เป็นทางเลือก |

## จาก `/createMessage`

รายการ v1 `notifications[*]` จะกลายเป็น request ของ `Notify` แต่ละรายการ (หนึ่งข้อความต่อรายการ) หากการเรียก v1 มีหลายรายการ ให้ส่ง `Notify` หนึ่งครั้งต่อหนึ่งรายการ

**การตัดสินใจเรื่องการกำหนดเป้าหมาย** หากรายการ v1 ใช้ `devices` หรือ `users` (รายการที่ระบุชัดเจน) ให้จับคู่กับ `transactional` มิฉะนั้นให้จับคู่กับ `segment`

### ฟิลด์ระดับ Request

- `application` → `segment.application` หรือ `transactional.application` (รูปแบบ app-code เดียวกัน)
- `applications_group`: ไม่รองรับใน v2 ใช้ request หลายรายการต่อแอป
- `auth`: ย้ายไปที่เฮดเดอร์ `Authorization` ไม่อยู่ใน body อีกต่อไป

### การตั้งเวลา

- `send_date` (`"YYYY-MM-DD HH:mm"` หรือ `"now"`) → `schedule.at` (การประทับเวลา RFC 3339 UTC) หากต้องการทำซ้ำ `"now"` ของ v1 ให้ตั้งค่า `schedule.at` เป็นเวลาปัจจุบัน การประทับเวลาใดๆ ในอดีตจะถูกส่งทันที
- `ignore_user_timezone` → `schedule.follow_user_timezone` **กลับกัน:** `ignore_user_timezone: true` จะกลายเป็น `follow_user_timezone: false`
- `timezone`: ไม่รองรับ v2 ใช้ UTC สำหรับ `at` เสมอ แปลงฝั่งไคลเอ็นต์

### การกำหนดเป้าหมาย

- `filter` (ชื่อ segment) → `segment.code`
- `conditions` (`[[tag, op, value], ...]`) → `segment.expression` เขียนใหม่เป็นนิพจน์ [seglang](/th/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` (hwids หรือ push tokens) → `transactional.hwids.list` หรือ `transactional.push_tokens.list` v2 แยกสองอย่างนี้: hwids ไปที่ `hwids`, push tokens ดิบไปที่ `push_tokens`
- `users` → `transactional.users.list`
- `platforms` (รหัสตัวเลข `[1, 3, …]`) → `segment.platforms` หรือ `transactional.platforms` (enums สตริง `["IOS", "ANDROID", …]`) ดูที่ [Platform enum](/th/developer/api-reference/messaging-api-v2/notify/#platform-enum)

### เนื้อหา

- `content` (สตริง) → `payload.content.localized_content.default.{platform}.body` ใน v2 เนื้อหาจะเป็นแบบต่อภาษาและต่อแพลตฟอร์มเสมอ ใส่สตริง v1 ธรรมดาไว้ใต้คีย์พิเศษ `"default"` (การแปลแบบครอบคลุมทั้งหมด ดูที่ [การเลือกภาษาสำหรับอุปกรณ์](/th/developer/api-reference/messaging-api-v2/payload-reference/#locale-selection-for-a-device))
- `content` (`{locale: text}`) → `payload.content.localized_content.{locale}.{platform}.body` ทำซ้ำ 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` → `dynamic_content_placeholders` บน `segment` หรือ `transactional`
- `campaign` → `campaign` บน `segment` หรือ `transactional`
- `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 พารามิเตอร์เหล่านี้จะย้ายเข้าไปอยู่ใน locale:

```
// 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" }
      }
    }
  }
}
```

ชื่อฟิลด์ภายในบล็อกแพลตฟอร์มอาจแตกต่างกันในบางที่ ดู [การอ้างอิง Payload](/th/developer/api-reference/messaging-api-v2/payload-reference/) สำหรับชื่อ v2 ที่ถูกต้อง

### ตัวอย่าง: ก่อนและหลัง

**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` ในกรณีส่วนใหญ่ หรือกับ `segment` หากคุณใช้เป็น `devices_filter` ข้ามแอปโดยไม่มีตัวระบุที่ชัดเจน

- `devices_filter` → `segment.expression` (seglang) หรือ `segment.filter_expression` (structured)
- `content` → `payload.content.localized_content.{locale}.{platform}.body`
- ฟิลด์อื่นๆ ทั้งหมด เหมือนกับ `/createMessage` ข้างต้น

## จาก `/createEmailMessage`

ย้ายไปที่ `Notify` ด้วย `platforms: ["EMAIL"]` และบล็อก `email_payload` การอ้างอิงฉบับเต็ม: [การอ้างอิง Email payload](/th/developer/api-reference/messaging-api-v2/email-payload-reference/)

- `subject` → `email_payload.subject` (map ที่ใช้ locale เป็นคีย์ ห่อค่าภาษาเดียวใน `{"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 (รหัสผู้ส่ง ฯลฯ) ยังคงมาจากกา​​รตั้งค่า SMS ของแอป แทนที่จะมาจาก body ของ request

## จาก `/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` ส่งโดย Meta เฉพาะภายในกรอบเวลาบริการลูกค้า 24 ชั่วโมง
- `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` (preset ทั่วไปที่ระดับ payload)
- การกำหนดเป้าหมาย: หมายเลขโทรศัพท์ WhatsApp ที่ใน v1 อยู่ใน `devices` (เช่น `"whatsapp:+1234567890"`) จะต้องลงทะเบียนผ่าน [`/registerDevice`](/th/developer/api-reference/device-api#registerdevice) กับผู้ใช้ ใน v2 กำหนดเป้าหมายผู้ใช้ผลลัพธ์ด้วย `transactional.users.list` (หรือ hwid ผ่าน `transactional.hwids.list`)
- `use_auto_registration`: ไม่รองรับ ลงทะเบียนหมายเลข WhatsApp ก่อนส่ง

## จาก `/createLineMessage`

ย้ายไปที่ `Notify` ด้วย `platforms: ["LINE"]` โดยใช้ `payload.content.localized_content.{locale}.line`:

- `content` (ข้อความธรรมดา) → `line.content`
- `preset` (รหัส preset ของ LINE) → `line.template` ฟิลด์ v2 จะเก็บรหัสที่อ้างอิงถึงเทมเพลต LINE ที่กำหนดค่าไว้ใน Pushwoosh Control Panel
- `template` แบบอินไลน์ (โครงสร้างข้อความรูปภาพ, carousel หรือ flex ของ v1): ไม่รองรับโดยตรงใน v2 กำหนดค่า rich message ล่วงหน้าเป็น preset ของ LINE ใน Control Panel และอ้างอิงผ่าน `line.template`
- การกำหนดเป้าหมาย: รายการ `devices` ของ v1 (LINE user IDs ที่ลงทะเบียนผ่าน SDK / `/registerDevice`) จะกลายเป็น `transactional.users.list` (หรือ hwid ผ่าน `transactional.hwids.list`) ใน v2

## ความแตกต่างของ Response

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": [...] }`) แทนที่จะเป็นคู่ `status_code` / `status_message` ของ v1