
# Tin nhắn & Cuộc hội thoại

Messages API cho phép bạn gửi tin nhắn cho bất kỳ liên hệ nào, đọc lại cuộc trò chuyện, chỉnh sửa hoặc xóa tin nhắn đã gửi, phản hồi tin nhắn, lấy toàn bộ chuỗi hội thoại, xuất bản ghi và đánh dấu tin nhắn là đã đọc hoặc chưa đọc — tất cả đều không cần mở hộp thư đến.

Tất cả các đường dẫn trên trang này đều tương đối so với URL cơ sở `https://api.youraiconnector.com/v1`. Mọi yêu cầu đều cần khóa API của bạn — xem [Xác thực](authentication.md) để biết danh sách đầy đủ các cách gửi khóa. Các ví dụ bên dưới sử dụng tiêu đề `X-API-Key`, với một ví dụ cURL cũng hiển thị biểu mẫu truy vấn `?apiKey=`.

> **Cách thức gửi hoạt động:** Việc gửi tin nhắn **không** chờ đợi tin nhắn đến nơi. API chấp nhận tin nhắn của bạn, trả về ngay lập tức với ID tin nhắn, sau đó gửi tin nhắn đó trong nền trên kênh của liên hệ (WhatsApp, SMS, Instagram, v.v.). Để theo dõi xem tin nhắn đã thực sự được gửi hoặc đọc hay chưa, hãy lắng nghe các cập nhật trạng thái bằng [Webhooks](webhooks.md) — đừng thực hiện thăm dò (poll). Phản hồi gửi chỉ xác nhận rằng tin nhắn đã được chấp nhận.

---

## Gửi tin nhắn

Có hai cách để gửi. Hãy chọn cách phù hợp với cách bạn đã xác định liên hệ:

- **Gửi theo ID liên hệ** — bạn đã biết ID của liên hệ (ví dụ: bạn đã tạo liên hệ thông qua API hoặc lấy từ webhook). Sử dụng `POST /contacts/{contactId}/send-message`.
- **Gửi theo định danh liên hệ** — bạn biết số điện thoại, ID Instagram, v.v. của liên hệ, nhưng không biết ID nội bộ của họ. Sử dụng `POST /contacts/send` và để nền tảng tìm liên hệ phù hợp.

Cả hai đều xếp hàng tin nhắn theo cùng một cách và gửi tin nhắn đó trên bất kỳ kênh nào mà liên hệ đang sử dụng. Bạn không cần chọn phương thức vận chuyển — nền tảng sẽ định tuyến các liên hệ WhatsApp qua WhatsApp, liên hệ SMS qua SMS, v.v.

### Gửi theo ID liên hệ

`POST /contacts/{contactId}/send-message`

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `body` | Có | Nội dung tin nhắn cần gửi. |
| `mediaUrl` | Không | URL của tệp phương tiện (hình ảnh, tài liệu, v.v.) cần đính kèm. |
| `mediaContentType` | Không | Loại MIME của phương tiện đính kèm, ví dụ: `image/jpeg`. |
| `pauseBot` | Không | `true` tạm dừng AI cho liên hệ này khi tin nhắn được gửi — dành cho trường hợp con người tiếp quản. Xem [Tạm dừng hoặc tiếp tục AI](#pause-or-resume-the-ai-for-one-contact). |
| `clearIncompleteReply` | Không | `true` hủy bỏ phản hồi bot đang viết dở để nó không tiếp tục sau tin nhắn của bạn. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/send-message" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi! Your appointment is confirmed for tomorrow at 10:00."
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/send-message",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      body: "Hi! Your appointment is confirmed for tomorrow at 10:00.",
    }),
  }
);
const data = await res.json();
console.log(data.messageId);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/send-message",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"body": "Hi! Your appointment is confirmed for tomorrow at 10:00."},
)
print(res.json()["messageId"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "messageId": "aB3dE5fG7hI9jK1lM2nO",
  "contactId": "contact123",
  "channel": "whatsapp",
  "message": "Message created successfully. Delivery is being processed."
}
```

### Gửi theo định danh liên hệ

`POST /contacts/send`

Sử dụng cách này khi bạn không có ID nội bộ của liên hệ. Cung cấp `body` tin nhắn cộng với **hoặc** là `contact_id`, **hoặc** là `channel` cùng với trường định danh khớp với kênh đó.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `body` | Có | Nội dung tin nhắn cần gửi. |
| `contact_id` | Không | ID của một liên hệ hiện có. Khi được thiết lập, các trường định danh bên dưới là không cần thiết. |
| `channel` | Không | Kênh để gửi tin nhắn. Bắt buộc khi `contact_id` không được cung cấp. Một trong 14 kênh có thể gửi đi: `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `telegram`, `chat-widget`, `custom`, `email`, `line`, `imessage`, `linkedin`, `viber`. |
| `phone_number` | Không | Số điện thoại của liên hệ theo định dạng quốc tế. Được sử dụng với `whatsapp`, `whatsapp_web`, và `sms`. |
| `instagram_id` | Không | ID người dùng Instagram của liên hệ. Được sử dụng với `instagram`. |
| `messenger_id` | Không | ID người dùng Messenger của liên hệ. Được sử dụng với `messenger`. |
| `telegram_user_id` | Không | ID người dùng Telegram của liên hệ. Được sử dụng với `telegram`. |
| `media_url` | Không | URL của tệp phương tiện cần đính kèm. |
| `media_content_type` | Không | Loại MIME của phương tiện đính kèm, ví dụ: `image/jpeg`. |

**Các kênh có thể được phân giải theo định danh.** Chỉ sáu trong số 14 kênh chấp nhận trường định danh thay vì `contact_id`: `whatsapp`, `whatsapp_web` và `sms` được tra cứu theo `phone_number`, `instagram` theo `instagram_id`, `messenger` theo `messenger_id`, và `telegram` theo `telegram_user_id`. Tám kênh còn lại — `instagram_private`, `chat-widget`, `custom`, `email`, `line`, `imessage`, `linkedin` và `viber` — không có định danh công khai để tra cứu, vì vậy việc gửi trên các kênh đó yêu cầu `contact_id`; chỉ truyền `channel` sẽ trả về `400` thông báo cho bạn biết rằng `contact_id` là bắt buộc.

**cURL** (sử dụng biểu mẫu truy vấn `?apiKey=`)

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "phone_number": "+31612345678",
    "body": "Hi! Your appointment is confirmed."
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/contacts/send", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    channel: "whatsapp",
    phone_number: "+31612345678",
    body: "Hi! Your appointment is confirmed.",
  }),
});
const data = await res.json();
console.log(data.message_id, data.channel);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/send",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "channel": "whatsapp",
        "phone_number": "+31612345678",
        "body": "Hi! Your appointment is confirmed.",
    },
)
data = res.json()
print(data["message_id"], data["channel"])
```

**Phản hồi** (`201 Created`):

```json
{
  "success": true,
  "message_id": "aB3dE5fG7hI9jK1lM2nO",
  "contact_id": "contact123",
  "channel": "whatsapp"
}
```

> **Lý do tin nhắn có thể bị từ chối:** Một liên hệ đang bật chế độ không làm phiền hoặc chế độ riêng tư không thể nhận tin nhắn gửi đi — yêu cầu sẽ thất bại với mã `422`. Nếu không có liên hệ nào khớp với ID hoặc định danh bạn đã cung cấp, bạn sẽ nhận được mã `404`.

---

## Liệt kê tin nhắn của một liên hệ

`GET /contacts/{contactId}/messages`

Trả về các tin nhắn của một liên hệ, tin nhắn mới nhất hiển thị trước, hỗ trợ phân trang dựa trên con trỏ.

| Tham số truy vấn | Bắt buộc | Mô tả |
|---|---|---|
| `limit` | Không | Kích thước trang. Mặc định là `50`, tối đa là `100`. |
| `cursor` | Không | Giá trị `next_cursor` từ phản hồi trước đó. Trả về các tin nhắn cũ hơn con trỏ này. |
| `filter` | Không | Lọc theo loại nội dung: `all` (mặc định), `text`, `media` hoặc `tool_use`. |
| `direction` | Không | Lọc theo hướng: `all` (mặc định), `inbound` (nhận từ liên hệ) hoặc `outbound` (gửi bởi bạn). |

> **Lưu ý về lọc và phân trang:** Các bộ lọc `filter` và `direction` được áp dụng cho từng trang sau khi trang đó được đọc, vì vậy một trang đã lọc có thể chứa ít mục hơn `limit`. Con trỏ `next_cursor` vẫn tiến triển qua toàn bộ cuộc hội thoại, vì vậy hãy tiếp tục phân trang cho đến khi `next_cursor` là `null`.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/contacts/contact123/messages?limit=50&direction=inbound" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ limit: "50", direction: "inbound" });
const res = await fetch(
  `https://api.youraiconnector.com/v1/contacts/contact123/messages?${params}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.messages, data.next_cursor);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"limit": 50, "direction": "inbound"},
)
data = res.json()
print(data["messages"], data["next_cursor"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "messages": [
    {
      "id": "aB3dE5fG7hI9jK1lM2nO",
      "body": "Hi! Thanks for reaching out.",
      "direction": "inbound",
      "channel": "whatsapp",
      "status": "delivered",
      "type": null,
      "timestamp": "2026-06-01T10:00:00.000Z",
      "media_url": null,
      "media_content_type": null,
      "bot_reply": false
    }
  ],
  "next_cursor": "cD4eF6gH8iJ0kL2mN3oP"
}
```

### Các trường tin nhắn

| Trường | Mô tả |
|---|---|
| `id` | ID duy nhất của tin nhắn. |
| `body` | Nội dung văn bản của tin nhắn. |
| `direction` | `inbound` (nhận từ liên hệ) hoặc `outbound` (được gửi bởi tài khoản của bạn). |
| `channel` | Kênh mà tin nhắn được gửi hoặc nhận (ví dụ: `whatsapp`, `sms`, `instagram`). |
| `status` | Trạng thái gửi hiện tại, ví dụ: `Created`, `sent`, `delivered`, `read`, `failed`. |
| `type` | Loại tin nhắn. Tin nhắn văn bản thuần có loại `null`; hoạt động của công cụ trợ lý tự động được đánh dấu là `tool_use`. |
| `timestamp` | Thời gian tạo tin nhắn theo chuẩn ISO 8601. |
| `media_url` | URL của tệp phương tiện đính kèm, nếu có. |
| `media_content_type` | Loại MIME của phương tiện đính kèm, nếu có. |
| `bot_reply` | `true` khi tin nhắn được tạo bởi trợ lý AI. |
| `score` | Đánh giá của bạn về tin nhắn: `1` thích, `-1` không thích, `0` khi chưa được đánh giá. Xem [Đánh giá hoặc gắn sao tin nhắn](#rate-or-star-a-message). |
| `is_important` | `true` khi tin nhắn đã được gắn sao. |
| `is_deleted` | `true` khi tin nhắn đã bị xóa. Tin nhắn đã xóa vẫn nằm trong danh sách nhưng `body` và `media_url` của chúng sẽ trống. |
| `reactions` | Các phản ứng bằng biểu tượng cảm xúc trên tin nhắn, từ cả hai phía. Luôn là một mảng — trống khi không có phản ứng nào. Mỗi mục có `emoji`, `from_phone_number`, `from_me` (`true` khi phản ứng là của bạn) và `reacted_at`. |

---

## Liệt kê các phiên trò chuyện

Một phiên trò chuyện là một cửa sổ hội thoại với một liên hệ: nó mở ra khi họ bắt đầu trò chuyện và đóng lại khi cuộc trò chuyện kết thúc. Các phiên là cách bạn phân trang lịch sử dài thành các cuộc hội thoại dễ đọc thay vì một danh sách vô tận.

### Các phiên gần đây trên tất cả liên hệ

`GET /chat-sessions/recent`

Trả về các phiên bắt đầu trong X giờ qua, mới nhất trước, trên tất cả liên hệ trong tài khoản.

| Tham số truy vấn | Bắt buộc | Mô tả |
|---|---|---|
| `hours` | Có | Xem lại bao nhiêu giờ trước. Phải là một số nguyên dương. |
| `status` | Không | Chỉ trả về các phiên có trạng thái này: `ChatSessionOpened` hoặc `ChatSessionClosed`. |
| `limit` | Không | Số lượng phiên tối đa cần trả về. Mặc định `100`, tối đa `100`. |
| `includeMessages` | Không | `true` thêm một mảng `messages` vào mỗi phiên. Mặc định tắt vì nó làm cho phản hồi lớn hơn nhiều. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-sessions/recent?hours=24&status=ChatSessionClosed" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ hours: "24", status: "ChatSessionClosed" });
const res = await fetch(`https://api.youraiconnector.com/v1/chat-sessions/recent?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.data.total_sessions, data.data.sessions);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/chat-sessions/recent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"hours": 24, "status": "ChatSessionClosed"},
)
data = res.json()["data"]
print(data["total_sessions"], data["sessions"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "hours_ago": 24,
    "total_sessions": 2,
    "sessions": [
      {
        "session_id": "session456",
        "contact_id": "contact123",
        "contact_name": "Jane Doe",
        "contact_phone": "+31612345678",
        "contact_email": "jane@example.com",
        "start_date_time": "2026-06-01T09:55:00.000Z",
        "end_date_time": "2026-06-01T10:20:00.000Z",
        "status": "ChatSessionClosed",
        "tag": "Booking enquiry"
      }
    ]
  }
}
```

### Tất cả các phiên cho một liên hệ

`GET /chat-sessions/{contactId}`

Trả về mọi phiên trò chuyện cho một liên hệ duy nhất. Các tham số `status`, `limit` và `includeMessages` giống như trên — `hours` không áp dụng ở đây.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-sessions/contact123?limit=20" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "contact_id": "contact123",
    "contact_name": "Jane Doe",
    "total_sessions": 2,
    "sessions": [
      {
        "id": "session456",
        "start_date_time": "2026-06-01T09:55:00.000Z",
        "end_date_time": "2026-06-01T10:20:00.000Z",
        "status": "ChatSessionClosed",
        "tag": "Booking enquiry"
      }
    ]
  }
}
```

> **Tên trường ID phiên khác nhau giữa hai điểm cuối.** Danh sách phiên gần đây gọi nó là `session_id` (nó cũng chứa chi tiết của liên hệ, vì các phiên đến từ nhiều liên hệ); danh sách theo liên hệ gọi nó là `id`. Giá trị nào cũng là thứ bạn truyền dưới dạng `{sessionId}` khi lấy toàn bộ chuỗi hội thoại bên dưới.

Khi `includeMessages=true`, mỗi phiên sẽ có thêm một mảng `messages` mà các mục của nó chứa `id`, `body`, `direction`, `timestamp`, `type`, `channel` và `status`.

---

## Lấy luồng phiên trò chuyện

`GET /contacts/{contactId}/chat-sessions/{sessionId}/messages`

Một phiên trò chuyện nhóm các tin nhắn của một liên hệ vào một cửa sổ hội thoại. Điểm cuối này trả về toàn bộ chuỗi của một phiên duy nhất, **theo thứ tự cũ nhất trước**, cùng với siêu dữ liệu của phiên đó. Bạn có thể tìm thấy ID phiên cho một liên hệ thông qua các điểm cuối phiên trò chuyện.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.session, data.messages);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["session"], data["messages"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "session": {
    "id": "session456",
    "status": "ChatSessionClosed",
    "start_date_time": "2026-06-01T09:55:00.000Z",
    "end_date_time": "2026-06-01T10:20:00.000Z",
    "tag": "Booking enquiry"
  },
  "messages": [
    {
      "id": "aB3dE5fG7hI9jK1lM2nO",
      "body": "Hi! Thanks for reaching out.",
      "direction": "inbound",
      "channel": "whatsapp",
      "status": "delivered",
      "type": null,
      "timestamp": "2026-06-01T09:55:00.000Z",
      "media_url": null,
      "media_content_type": null,
      "bot_reply": false
    }
  ]
}
```

Đối tượng `session` báo cáo `status` (`ChatSessionOpened` khi đang hoạt động, `ChatSessionClosed` sau khi kết thúc), `start_date_time`, `end_date_time` và một `tag` dễ đọc. Mảng `messages` sử dụng cùng các [trường tin nhắn](#message-fields) như điểm cuối danh sách.

---

## Chỉnh sửa, xóa và phản hồi tin nhắn

Các điểm cuối này thay đổi tin nhắn sau khi nó đã được gửi. Hai trong số đó tiếp cận kênh của liên hệ cũng như bản sao của riêng bạn, vì vậy hãy đọc phần giới thiệu trước khi kết nối chúng — những gì có thể thực hiện phụ thuộc hoàn toàn vào kênh mà cuộc trò chuyện đang diễn ra.

**Mỗi kênh cho phép những gì**

| Hành động | Các kênh có thể thay đổi bản sao của liên hệ | Giới hạn thời gian |
|---|---|---|
| Chỉnh sửa tin nhắn đã gửi | Tiện ích trò chuyện, WhatsApp Web, Telegram, LinkedIn | Không giới hạn trên tiện ích trò chuyện, 15 phút trên WhatsApp Web, 48 giờ trên Telegram, 60 phút trên LinkedIn |
| Xóa cho mọi người | Tiện ích trò chuyện, WhatsApp Web, Telegram, LinkedIn | 60 phút trên LinkedIn; các kênh khác không có giới hạn được công bố |
| Phản ứng bằng biểu tượng cảm xúc | WhatsApp Web, Telegram | Không có |

Trên mọi kênh khác — WhatsApp Business API, SMS, Instagram, Messenger, email, LINE, các kênh tùy chỉnh — việc xóa vẫn loại bỏ tin nhắn khỏi hộp thư đến của bạn, nhưng liên hệ vẫn giữ bản sao của họ, và việc chỉnh sửa hoặc phản ứng hoàn toàn không thể thực hiện được.

### Chỉnh sửa tin nhắn

`POST /contacts/{contactId}/messages/{messageId}/edit`

Viết lại tin nhắn bạn đã gửi, trên thiết bị của liên hệ và trong bản sao của bạn.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `body` | Có | Nội dung tin nhắn mới. Không được để trống và tối đa 4096 ký tự. |

Không giống như việc xóa, hành động này sẽ **thông báo lỗi rõ ràng** khi kênh từ chối: bạn nhận được `409` và bản sao của bạn vẫn giữ nguyên như bản sao của liên hệ, vì việc hiển thị một chỉnh sửa mà họ không bao giờ nhận được sẽ khiến hai bên không đồng bộ. Trường `edit_reason` cho bạn biết lý do — cửa sổ chỉnh sửa của kênh đã đóng, kênh đã bị ngắt kết nối hoặc có lỗi khác xảy ra.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "body": "Sorry - I meant Thursday at 3pm." }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ body: "Sorry - I meant Thursday at 3pm." }),
  }
);
const data = await res.json();
console.log(data.edited, data.edit_reason);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"body": "Sorry - I meant Thursday at 3pm."},
)
data = res.json()
print(data.get("edited"), data.get("edit_reason"))
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "edited": true,
  "edit_reason": "edit_dispatched"
}
```

Nếu kênh không chấp nhận chỉnh sửa, bạn sẽ nhận được `409` thay vào đó và không có gì thay đổi:

```json
{
  "success": false,
  "error": "The message could not be edited",
  "edit_reason": "channel_disconnected"
}
```

Một tin nhắn đã bị xóa, một kênh không thể chỉnh sửa và một tin nhắn quá cũ so với kênh của nó đều trả về `400` — yêu cầu không bao giờ đến được kênh.

### Xóa một tin nhắn

`DELETE /contacts/{contactId}/messages/{messageId}`

Xóa tin nhắn khỏi cuộc trò chuyện của bạn và, nếu kênh cho phép, sẽ thu hồi cả bản sao của liên hệ. Không có phần thân yêu cầu.

Hành động này luôn trả về `200` khi tin nhắn tồn tại, ngay cả khi bản sao của liên hệ không thể thu hồi — bản sao của bạn **đã** bị xóa, vì vậy một lỗi sẽ gây hiểu lầm. Hãy đọc ba trường trong phản hồi để thông báo cho người dùng những gì thực sự đã xảy ra:

| Trường | Mô tả |
|---|---|
| `revoke_supported` | Liệu kênh này có thể thu hồi tin nhắn hay không. |
| `revoked` | Liệu bản sao trên thiết bị của liên hệ đã bị xóa hay chưa. |
| `revoke_reason` | Lý do tại sao nó không bị xóa, khi `revoked` là `false` — ví dụ `revoke_window_closed` hoặc `already_deleted`. |

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.revoked, data.revoke_reason);
```

**Python**

```python
import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["revoked"], data["revoke_reason"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "revoke_supported": true,
  "revoked": true,
  "revoke_reason": "revoke_dispatched"
}
```

> Các tin nhắn đã xóa không bị loại bỏ khỏi lịch sử cuộc trò chuyện. Chúng vẫn nằm trong `GET /contacts/{contactId}/messages` với `is_deleted: true` cùng một `body` và `media_url` trống.

### Xóa nhiều tin nhắn cùng lúc

`POST /contacts/{contactId}/messages/bulk-delete`

Xóa một loạt tin nhắn chỉ từ phía bạn. Nội dung và tệp đính kèm sẽ bị xóa sạch, nhưng **không có gì bị thu hồi trên thiết bị của người liên hệ** — để thu hồi tin nhắn, hãy xóa từng tin một bằng điểm cuối tin nhắn đơn lẻ ở trên.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `message_ids` | Có | Một mảng không trống chứa các ID tin nhắn, tối đa 500 ID mỗi yêu cầu. `messageIds` được chấp nhận như một bí danh. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message_ids": ["msg_1", "msg_2"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ message_ids: ["msg_1", "msg_2"] }),
  }
);
console.log((await res.json()).deleted);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"message_ids": ["msg_1", "msg_2"]},
)
print(res.json()["deleted"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "deleted": 2
}
```

### Phản ứng với một tin nhắn

`POST /contacts/{contactId}/messages/{messageId}/react`

Đặt phản ứng bằng biểu tượng cảm xúc của riêng bạn lên một tin nhắn, hoặc thu hồi lại bằng cách gửi một chuỗi trống. Các phản ứng của người liên hệ sẽ không bao giờ bị ảnh hưởng.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `emoji` | Có | Biểu tượng cảm xúc để phản ứng, hoặc `""` để xóa phản ứng của bạn. Phải là một chuỗi đơn không có khoảng trắng, tối đa 16 ký tự. |

Giống như việc chỉnh sửa, thao tác này sẽ thất bại thay vì hiển thị một phản ứng mà người liên hệ chưa bao giờ nhận được, và thông báo lỗi sẽ cho bạn biết liệu có nên thử lại hay không:

- `422` — không bao giờ có thể gửi được trong cuộc trò chuyện này: kênh không hỗ trợ phản ứng, tin nhắn không có ID phía kênh, hoặc biểu tượng cảm xúc nằm ngoài tập hợp mà kênh cho phép.
- `409` — kênh tạm thời không thể truy cập được. Thử lại có thể sẽ thành công.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emoji": "👍" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ emoji: "👍" }),
  }
);
const data = await res.json();
console.log(data.reactions);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"emoji": "👍"},
)
print(res.json()["reactions"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "reaction_supported": true,
  "reaction_reason": "reaction_dispatched",
  "reactions": [
    {
      "emoji": "👍",
      "from_phone_number": "+31612345678",
      "from_me": true,
      "reacted_at": "2026-06-01T10:05:00.000Z"
    }
  ]
}
```

Mảng `reactions` là tập hợp đầy đủ các phản ứng hiện có trên tin nhắn, bao gồm cả của bạn và của người liên hệ. Trên `409` hoặc `422`, nó được trả về nguyên trạng, vì vậy ứng dụng khách hiển thị trực tiếp từ đó sẽ không bao giờ hiển thị một phản ứng chưa được gửi đi.

### Đánh giá hoặc gắn sao cho tin nhắn

`PATCH /contacts/{contactId}/messages/{messageId}`

Đánh giá tin nhắn bằng ngón tay cái hướng lên hoặc hướng xuống và/hoặc gắn sao cho tin nhắn đó là quan trọng. Đây chỉ là việc ghi chép ở phía bạn — không có gì được gửi đến người liên hệ.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `score` | Không | `1` thích, `-1` không thích, `0` xóa đánh giá. |
| `is_important` | Không | `true` gắn sao tin nhắn, `false` bỏ gắn sao. Phải là giá trị boolean thực, không phải chuỗi `"true"`. |

Hãy gửi ít nhất một trong hai, nếu không bạn sẽ nhận được `400`. Chỉ những gì bạn gửi mới được ghi lại, vì vậy việc gắn sao tin nhắn sẽ không bao giờ xóa đánh giá của nó và ngược lại — và phản hồi chỉ trả về các trường bạn đã gửi.

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "score": 1, "is_important": true }'
```

**JavaScript**

```javascript
await fetch("https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1", {
  method: "PATCH",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ score: 1, is_important: true }),
});
```

**Python**

```python
import requests

requests.patch(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"score": 1, "is_important": True},
)
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "score": 1,
  "is_important": true
}
```

---

## Đánh dấu tin nhắn là đã đọc

Bạn có thể xóa trạng thái chưa đọc cho các tin nhắn cụ thể hoặc cho toàn bộ cuộc hội thoại.

### Đánh dấu các tin nhắn cụ thể là đã đọc

`POST /contacts/{contactId}/messages/mark-read`

Chuyển các ID của tin nhắn cần đánh dấu là đã đọc.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `message_ids` | Có | Một mảng không trống chứa các ID tin nhắn (tối đa 500 ID mỗi yêu cầu). |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message_ids": ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      message_ids: ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"],
    }),
  }
);
const data = await res.json();
console.log(data.marked_read);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"message_ids": ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"]},
)
print(res.json()["marked_read"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "marked_read": 2
}
```

### Đánh dấu toàn bộ cuộc trò chuyện là đã đọc

`POST /contacts/{contactId}/mark-read`

Xóa huy hiệu chưa đọc cho toàn bộ cuộc hội thoại của liên hệ trong hộp thư đến. Không yêu cầu phần thân yêu cầu.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/mark-read" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/mark-read",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.success);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/mark-read",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

### Đánh dấu toàn bộ cuộc trò chuyện là chưa đọc

`POST /contacts/{contactId}/mark-unread`

Đặt lại huy hiệu chưa đọc vào cuộc trò chuyện — hữu ích khi ai đó trong nhóm của bạn đã mở cuộc trò chuyện nhưng đang bàn giao lại. Không yêu cầu nội dung yêu cầu (request body).

Đây là cờ chỉ dành cho hộp thư đến: nó **không** thay đổi thời điểm cuộc trò chuyện được đọc lần cuối, vì vậy không có biên nhận đã đọc nào được gửi đến liên hệ trên các kênh hỗ trợ tính năng này.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/mark-unread" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

---

## Xuất cuộc trò chuyện

Việc xuất dữ liệu cung cấp cho bạn toàn bộ cuộc trò chuyện dưới dạng bản ghi có thể đọc được, thay vì phải lật qua từng tin nhắn. Mọi điểm cuối xuất dữ liệu đều chấp nhận `filter` là `all` (mặc định), `text`, `media` hoặc `tool_use`, khớp với bộ lọc trên danh sách tin nhắn.

### Xuất cuộc trò chuyện của một liên hệ

`GET /chat-exports/{contactId}`

| Tham số truy vấn | Bắt buộc | Mô tả |
|---|---|---|
| `format` | Không | `txt` (mặc định) trả về liên kết tải xuống bản ghi văn bản thuần túy. `json` trả về các tin nhắn dưới dạng dữ liệu có cấu trúc trong phản hồi. |
| `filter` | Không | `all` (mặc định), `text`, `media` hoặc `tool_use`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-exports/contact123?format=json" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/chat-exports/contact123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"format": "json"},
)
print(res.json()["data"]["messages"])
```

**Phản hồi với `format=json`** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "contact": {
      "id": "contact123",
      "name": "Jane Doe",
      "phone": "+31612345678",
      "email": "jane@example.com"
    },
    "messages": [
      {
        "body": "Hi! I have a question about my order.",
        "direction": "inbound",
        "timestamp": "2026-06-01T09:55:00.000Z",
        "type": "text",
        "media_url": null,
        "media_content_type": null,
        "name": null,
        "args": null
      }
    ]
  }
}
```

Với `format=txt` (mặc định), `data` thay vào đó là liên kết tải xuống tệp bản ghi đã tạo:

```json
{
  "success": true,
  "data": "https://storage.googleapis.com/.../chat-export-contact123-....txt"
}
```

> **Liên kết tải xuống có thời hạn ngắn.** Hãy tải tệp ngay khi bạn nhận được liên kết thay vì lưu trữ nó — hãy yêu cầu xuất mới khi bạn cần lại bản ghi.

### Xuất mọi cuộc trò chuyện gần đây

`GET /chat-exports/recent`

Xuất các cuộc hội thoại của tất cả các liên hệ đã hoạt động trong X giờ qua, chỉ trong một lệnh gọi.

| Tham số truy vấn | Bắt buộc | Mô tả |
|---|---|---|
| `hours` | Có | Số giờ hoạt động cần xem xét lại. Phải là một số nguyên dương. |
| `format` | Không | `json` (mặc định) trả về một mục cho mỗi liên hệ. `txt` trả về một tệp văn bản duy nhất có thể tải xuống chứa mọi cuộc hội thoại. |
| `limit` | Không | Số lượng liên hệ tối đa để xuất. Mặc định là `50`, tối đa là `100`. |
| `filter` | Không | `all` (mặc định), `text`, `media` hoặc `tool_use`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-exports/recent?hours=24&limit=25" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "hours_ago": 24,
    "total_contacts": 2,
    "exports": [
      {
        "contactId": "contact123",
        "contactName": "Jane Doe",
        "phoneNumber": "+31612345678",
        "email": "jane@example.com",
        "messageCount": 12,
        "chatExport": "Acme Export - Jane Doe\nPhone: +31612345678\n..."
      }
    ]
  }
}
```

Với `format=txt`, phản hồi sẽ là chính tệp văn bản đó, được gửi dưới dạng tệp tải xuống thay vì JSON.

> Lệnh gọi này lấy toàn bộ lịch sử của mọi liên hệ khớp, vì vậy hãy giữ `hours` và `limit` ở mức vừa phải trên các tài khoản bận rộn.

### Gửi bản ghi cuộc hội thoại qua email cho liên hệ

`POST /chat-exports/{contactId}/email`

Gửi cho liên hệ bản ghi cuộc hội thoại của chính họ qua email — quy trình "gửi cho tôi cuộc trò chuyện này qua email", được điều khiển từ hệ thống của riêng bạn.

| Trường | Bắt buộc | Mô tả |
|---|---|---|
| `recipient_email` | Không | Nơi gửi email. Mặc định là địa chỉ email đã lưu của liên hệ. |
| `via` | Không | `auto` (mặc định) chọn lộ trình tốt nhất, `transactional` gửi dưới dạng email hệ thống, `email_channel` gửi từ kênh email đã kết nối của bạn. |
| `note` | Không | Một dòng ngắn từ bạn hiển thị phía trên bản ghi cuộc hội thoại. Tối đa 1000 ký tự. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/chat-exports/contact123/email" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "note": "Here is a copy of our chat, as promised." }'
```

**Phản hồi** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "via": "transactional",
    "recipientEmail": "jane@example.com",
    "messageCount": 42,
    "omittedCount": 0
  }
}
```

`omittedCount` cho bạn biết có bao nhiêu tin nhắn cũ nhất đã bị lược bỏ để giữ cho email có độ dài hợp lý. `200` có nghĩa là bản ghi cuộc hội thoại đã được tạo và đưa vào hàng đợi để gửi, không có nghĩa là nó đã đến hộp thư đến.

---

## Tạm dừng hoặc tiếp tục AI cho một liên hệ

`PUT /contacts/{contactId}`

Đặt `is_bot_active` thành `false` để ngăn AI trả lời một liên hệ và đặt lại thành `true` để bàn giao lại cuộc trò chuyện. Đây là công tắc tiếp quản bạn cần khi một người thật tham gia vào cuộc trò chuyện: các tin nhắn gửi đi mà bạn gửi bằng API vẫn được chuyển đi trong khi bot đang bị tạm dừng.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/contacts/contact123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_bot_active": false }'
```

**JavaScript**

```javascript
await fetch("https://api.youraiconnector.com/v1/contacts/contact123", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ is_bot_active: false }),
});
```

**Python**

```python
import requests

requests.put(
    "https://api.youraiconnector.com/v1/contacts/contact123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"is_bot_active": False},
)
```

**Phản hồi**

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

**Tạm dừng như một phần của phản hồi**

Nếu một người thật đang tiếp quản bằng cách gửi phản hồi, bạn có thể tạm dừng bot trong cùng một yêu cầu thay vì thực hiện cuộc gọi thứ hai. `POST /contacts/{contactId}/send-message` chấp nhận hai cờ tùy chọn:

| Trường | Mô tả |
|---|---|
| `pauseBot` | `true` tạm dừng AI cho liên hệ này khi tin nhắn được gửi. |
| `clearIncompleteReply` | `true` hủy bỏ phản hồi bot đang viết dở để nó không tiếp tục sau đó. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/send-message" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi, Sarah here - taking over from the assistant.",
    "pauseBot": true,
    "clearIncompleteReply": true
  }'
```

Phản hồi bao gồm `"botPaused": true` khi lệnh tạm dừng đã được áp dụng.

> Đánh dấu một liên hệ là riêng tư với [`POST /contacts/bulk-flag`](contacts.md) cũng sẽ tạm dừng bot đối với họ. Xem [Liên hệ](contacts.md) để biết danh sách đầy đủ các trường.

---

## Xây dựng hộp thư đến của riêng bạn

Mọi thứ mà một hộp thư đến cần đều có trên trang này và trong [Liên hệ](contacts.md):

| Những gì bạn cần | Điểm cuối |
|---|---|
| Liệt kê các cuộc hội thoại | `GET /contacts` |
| Đọc một cuộc hội thoại | `GET /contacts/{contactId}/messages` |
| Liệt kê các phiên trò chuyện của liên hệ | `GET /chat-sessions/{contactId}` |
| Xem những gì đã nhận gần đây | `GET /chat-sessions/recent` |
| Đọc một phiên trò chuyện | `GET /contacts/{contactId}/chat-sessions/{sessionId}/messages` |
| Gửi trả lời thủ công | `POST /contacts/{contactId}/send-message` |
| Chỉnh sửa câu trả lời bạn vừa gửi | `POST /contacts/{contactId}/messages/{messageId}/edit` |
| Xóa một tin nhắn | `DELETE /contacts/{contactId}/messages/{messageId}` |
| Xóa nhiều tin nhắn | `POST /contacts/{contactId}/messages/bulk-delete` |
| Phản ứng bằng biểu tượng cảm xúc | `POST /contacts/{contactId}/messages/{messageId}/react` |
| Đánh giá hoặc gắn sao một tin nhắn | `PATCH /contacts/{contactId}/messages/{messageId}` |
| Đánh dấu là đã đọc | `POST /contacts/{contactId}/mark-read` |
| Chuyển lại cuộc trò chuyện cho nhóm | `POST /contacts/{contactId}/mark-unread` |
| Xuất bản ghi cuộc hội thoại | `GET /chat-exports/{contactId}` |
| Tạm dừng hoặc tiếp tục AI | `PUT /contacts/{contactId}` với `is_bot_active` |

Để nhận cập nhật trực tiếp, hãy đăng ký các sự kiện `New Message`, `Replies`, `Human Alerted` và `Chat Concluded` bằng [Webhooks](webhooks.md) thay vì thăm dò API này theo bộ hẹn giờ.

---

## Các lỗi của Messages API

Các điểm cuối (endpoint) tin nhắn trả về phong bì lỗi tiêu chuẩn:

```json
{
  "success": false,
  "error": "Contact not found"
}
```

| Trạng thái | Khi nào nó xảy ra trên điểm cuối tin nhắn |
|---|---|
| `400` | Thiếu trường bắt buộc hoặc tham số không hợp lệ (`limit`, `hours`, `filter`, `direction`, `status` sai, mảng `message_ids` trống hoặc trên 500, `cursor` không hợp lệ, chỉnh sửa `body` trống hoặc quá dài, `score` nằm ngoài `-1`/`0`/`1`, hoặc biểu tượng cảm xúc có dấu cách hoặc trên 16 ký tự). Cũng được trả về khi tin nhắn không thể chỉnh sửa được — tin nhắn đã bị xóa, kênh của nó không hỗ trợ chỉnh sửa, hoặc đã quá thời hạn chỉnh sửa của kênh đó. |
| `404` | Không tìm thấy liên hệ, phiên trò chuyện hoặc một trong các ID tin nhắn được cung cấp. |
| `409` | Kênh không chấp nhận thay đổi vào lúc này. Không có gì được ghi lại: khi chỉnh sửa, `edit_reason` cho biết lý do; khi phản ứng, kênh tạm thời không thể truy cập được và việc thử lại có thể hiệu quả. |
| `422` | Liên hệ không thể nhận tin nhắn gửi đi (không làm phiền, riêng tư hoặc kênh không được hỗ trợ), hoặc phản ứng không bao giờ có thể được gửi trong cuộc hội thoại này (`reaction_reason` cho biết lý do). |

Các mã chung mà mọi điểm cuối có thể trả về — `401`, `403` (gói của bạn không bao gồm quyền truy cập API), `429` (giới hạn tốc độ) và `500` — được liệt kê cùng với hướng dẫn thử lại trong [Lỗi & Phân trang](errors-and-pagination.md).

---

## Các bước tiếp theo

- [Webhooks](webhooks.md) — nhận cập nhật trạng thái gửi tin nhắn được đẩy tới thay vì phải thăm dò (polling).
- [Liên hệ](contacts.md) — tạo và tra cứu các liên hệ mà bạn nhắn tin.
- [Cuộc hẹn](appointments.md) — đặt và quản lý cuộc hẹn cho các liên hệ của bạn.
