
# API Phân tích & Báo cáo

Các endpoint chỉ đọc này cho phép bạn lấy dữ liệu hoạt động của tài khoản vào bảng điều khiển và báo cáo của riêng bạn: số lượng sự kiện tin nhắn, mức tiêu thụ tín dụng, chi phí AI, cùng các biểu đồ và thông tin chi tiết giống như trên bảng điều khiển trong ứng dụng. Hướng dẫn này bao gồm:

- **Tóm tắt** — các bộ đếm lưu lượng tin nhắn (đã gửi, đã chuyển, đã đọc, đã trả lời, đã đặt lịch, liên hệ được tạo, tín dụng).
- **Tín dụng** — sổ cái chi tiết, được phân trang về việc sử dụng tín dụng với tổng số và phân tích chi tiết.
- **Chi phí AI** — tổng hợp chi phí AI theo ngày.
- **Chuỗi chỉ số** — chuỗi thời gian sẵn sàng cho biểu đồ của một hoặc nhiều chỉ số, được nhóm theo chiến dịch, kênh, AI Agent hoặc số điện thoại.
- **Kết quả hội thoại** — cách các cuộc hội thoại kết thúc, theo thẻ kết quả do AI gán.
- **Thông tin chi tiết bảng điều khiển** và **Thông tin chi tiết AI bảng điều khiển** — toàn bộ dữ liệu đằng sau bảng điều khiển trong ứng dụng, bao gồm cả các bản tóm tắt do AI viết.
- **Hoạt động của thực thể** — dòng thời gian của một liên hệ, giao dịch hoặc tác vụ cụ thể.
- **Số lượng sự kiện tổng hợp** — định dạng camelCase kế thừa của Tóm tắt được giữ lại cho các tích hợp hiện có.

Mỗi endpoint trên trang này cần một phạm vi chính xác, không được dùng cả hai: chỉ truyền tối đa một trong `campaign_id` (kế thừa) hoặc `agent_id` tại nơi endpoint chấp nhận. Gửi cả hai sẽ trả về `400`, và một id không có trong tài khoản của bạn sẽ trả về `404` thay vì `403`, để id của các tài khoản khác không thể đoán được.

Tất cả các đường dẫn bên dưới đều tương đối so với URL cơ sở của API:

```
https://api.youraiconnector.com/v1
```

Mọi yêu cầu đều phải được xác thực. Xem [Xác thực](authentication.md) để biết bốn phương thức được chấp nhận. Các ví dụ ở đây sử dụng tiêu đề `X-API-Key` (và một dạng tham số truy vấn cho cURL).

---

## Phạm vi ngày

Cả ba điểm cuối đều chấp nhận các bộ lọc ngày tùy chọn giống nhau:

| Tham số | Mô tả |
|---|---|
| `from` | Bắt đầu phạm vi, `YYYY-MM-DD`, bao gồm cả ngày bắt đầu. Mặc định là 30 ngày trước. |
| `to` | Kết thúc phạm vi, `YYYY-MM-DD`, bao gồm cả ngày kết thúc. Mặc định là hôm nay. |

Ngày được hiểu theo giờ UTC. Phạm vi mặc định là **30 ngày qua** và được giới hạn ở mức **366 ngày** — phạm vi rộng hơn sẽ trả về `400`. `from` không được sau `to`.

### Cờ `truncated`

Các điểm cuối **Tóm tắt** và **Tín dụng** giới hạn số lượng bản ghi mà một yêu cầu duy nhất quét. Nếu phạm vi của bạn đủ bận để đạt đến giới hạn đó, phản hồi sẽ bao gồm `"truncated": true`. Khi bạn thấy nó, các con số dựa trên quá trình quét một phần — hãy thu hẹp phạm vi ngày của bạn (hoặc phân trang với cửa sổ nhỏ hơn) để có được số liệu đầy đủ.

::: note
**Lưu ý:** Các số liệu về chi phí và token chỉ được bao gồm cho các lệnh gọi AI được tính phí vào khóa API nhà cung cấp của riêng bạn. Khi các số liệu chi phí bị ẩn đối với tài khoản của bạn, phản hồi sẽ đặt `"costs_redacted": true` và các trường chi phí sẽ được trả về bằng không.
:::


---

## Tóm tắt lưu lượng tin nhắn

Trả về các bộ đếm sự kiện tin nhắn tổng hợp cho tài khoản của bạn, dưới dạng tổng phạm vi và chuỗi theo ngày. Mỗi ngày trong phạm vi xuất hiện trong `by_date` — những ngày không có hoạt động sẽ được điền bằng 0. Tùy chọn lọc theo một chiến dịch duy nhất với `campaign_id`.

`GET /analytics/summary`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `from` | Không | Bắt đầu phạm vi, `YYYY-MM-DD`. |
| `to` | Không | Kết thúc phạm vi, `YYYY-MM-DD`. |
| `campaign_id` | Không | Chỉ đếm các sự kiện thuộc chiến dịch này. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/summary?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/summary?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/summary",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total": 1240,
    "sent": 800,
    "delivered": 760,
    "read": 540,
    "replied": 210,
    "booked": 35,
    "contact_created": 120,
    "credits_spent": 412.5,
    "credits_recharged": 500
  },
  "by_date": [
    {
      "date": "2026-05-01",
      "total": 40,
      "sent": 25,
      "delivered": 24,
      "read": 18,
      "replied": 7,
      "booked": 1,
      "contact_created": 4,
      "credits_spent": 13.5,
      "credits_recharged": 0
    }
  ],
  "truncated": false
}
```

Mỗi mục trong `by_date` có các trường bộ đếm giống như `totals`, cộng thêm một `date`.

Nếu bạn truyền một `campaign_id` không thuộc tài khoản của mình, phản hồi sẽ là `404` với `{ "success": false, "error": "Campaign not found" }`.

---

## Sử dụng tín dụng

Trả về mức sử dụng tín dụng trong phạm vi: một danh sách phân trang các bản ghi riêng lẻ, cộng với tổng phạm vi và phân tích theo lý do và theo chiến dịch.

`GET /analytics/credits`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `from` | Không | Bắt đầu phạm vi, `YYYY-MM-DD`. |
| `to` | Không | Kết thúc phạm vi, `YYYY-MM-DD`. |
| `campaign_id` | Không | Chỉ bao gồm mức sử dụng được quy cho chiến dịch này. |
| `limit` | Không | Kích thước trang cho `records`, 1–100. Mặc định là 50. |
| `cursor` | Không | Truyền `next_cursor` của trang trước để lấy trang tiếp theo. |

> **Điều chỉnh so với tiêu thụ:** Các thay đổi số dư như tiền thưởng, gia hạn gói và hiệu chỉnh được **loại trừ** khỏi `totals` và các phân tích — chúng không phải là mức tiêu thụ thực tế. Chúng vẫn xuất hiện trong danh sách `records`, được gắn cờ với `"is_adjustment": true`.

**Tổng và phân tích chỉ xuất hiện trên trang đầu tiên** (khi không có `cursor` nào được cung cấp). Trên các trang sau, `totals`, `by_reason`, `by_reason_cost` và `by_campaign` được trả về dưới dạng `null` — chỉ có mảng `records` là tiếp tục. Điều này tránh việc phải quét lại toàn bộ phạm vi cho mỗi trang.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/credits?from=2026-05-01&to=2026-05-31&limit=50&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  limit: "50",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/credits?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

// To page: pass data.next_cursor as ?cursor on the next request, until it is null.
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/credits",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31", "limit": 50},
)
data = res.json()

# To page: pass data["next_cursor"] as cursor on the next request, until it is None.
```

**Phản hồi** (trang đầu tiên)

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "credits_used": 412.5,
    "cost_usd": 1.284512,
    "records": 318
  },
  "by_reason": {
    "AI Message": 380.0,
    "Campaign Message": 32.5
  },
  "by_reason_cost": {
    "AI Message": 1.284512,
    "Campaign Message": 0
  },
  "by_campaign": {
    "Spring Promo": 250.0,
    "Reactivation": 162.5
  },
  "records": [
    {
      "id": "rec_abc123",
      "amount": 1,
      "timestamp": "2026-05-31T14:02:11.000Z",
      "reason": "AI Message",
      "is_adjustment": false,
      "campaign_id": "campaign123",
      "campaign_name": "Spring Promo",
      "contact_id": "contact456",
      "contact_name": "Jane Smith",
      "credit_type": "ai",
      "custom_keys_used": false,
      "description": null,
      "cost_usd": 0,
      "input_tokens": 0,
      "output_tokens": 0,
      "cache_read_tokens": 0,
      "cache_creation_tokens": 0,
      "ai_model": null,
      "request_id": null,
      "is_test": false
    }
  ],
  "next_cursor": "rec_abc123",
  "costs_redacted": false,
  "truncated": false
}
```

**Ghi chú trường:**

- `amount` — tín dụng bị tính phí cho bản ghi. Bằng không đối với các bản ghi được tính phí vào khóa API nhà cung cấp của riêng bạn.
- `is_adjustment` — `true` cho các thay đổi số dư (được loại trừ khỏi tổng/phân tích).
- `cost_usd`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_creation_tokens`, `ai_model`, `request_id` — chỉ được điền trên các bản ghi được tính phí vào khóa API nhà cung cấp của riêng bạn; bằng không hoặc `null` nếu không.
- `is_test` — `true` cho các lần chạy thử nghiệm/playground, vốn không bao giờ bị tính phí.
- `next_cursor` — con trỏ cho trang tiếp theo, hoặc `null` khi không còn bản ghi nào nữa.

---

## Tổng hợp chi phí AI

Trả về tổng hợp chi phí AI theo ngày cho tài khoản của bạn. Dữ liệu này đọc các tổng số hàng ngày đã được tổng hợp trước, vì vậy nó rất nhanh ngay cả trong phạm vi dài. Mỗi ngày trong phạm vi đều xuất hiện trong `days` — những ngày không có hoạt động sẽ được điền bằng không.

`GET /analytics/ai-cost`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `from` | Không | Điểm bắt đầu phạm vi, `YYYY-MM-DD`. |
| `to` | Không | Điểm kết thúc phạm vi, `YYYY-MM-DD`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/ai-cost?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/ai-cost?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/ai-cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "totals": {
    "total_usd": 12.4821,
    "byok_usd": 12.4821,
    "platform_usd": 0,
    "calls": 4210
  },
  "days": [
    {
      "date": "2026-05-01",
      "total_usd": 0.4012,
      "byok_usd": 0.4012,
      "platform_usd": 0,
      "input_usd": 0.18,
      "output_usd": 0.19,
      "cache_creation_usd": 0.02,
      "cache_read_usd": 0.0112,
      "calls": 140,
      "by_provider": { "anthropic": 0.4012 }
    }
  ],
  "costs_redacted": false
}
```

**Ghi chú trường:**

- `byok_usd` — chi phí được tính vào các khóa API nhà cung cấp của riêng bạn.
- `platform_usd` — phần chi phí chạy trên nền tảng thay vì khóa của riêng bạn.
- `input_usd`, `output_usd`, `cache_creation_usd`, `cache_read_usd` — các thành phần chi phí tạo nên `total_usd`.
- `by_provider` — chi phí bằng USD được phân loại theo tên nhà cung cấp AI.
- Các số liệu USD chỉ được trả về cho các tài khoản sử dụng khóa nhà cung cấp của riêng họ. Đối với các tài khoản thanh toán bằng tín dụng, mọi trường USD đều bằng 0 và `costs_redacted` là `true` (số lượng cuộc gọi vẫn hiển thị).

---

## Chuỗi chỉ số

Trả về một hoặc nhiều chuỗi thời gian chỉ số trong một lần gọi, tùy chọn nhóm theo tối đa hai chiều — endpoint để liên kết với biểu đồ. Một yêu cầu duy nhất có thể trả lời "số lượng đã gửi và đã trả lời mỗi ngày, theo mỗi kênh, cho chiến dịch này" mà không cần thực hiện mỗi cuộc gọi cho mỗi chiến dịch.

`GET /analytics/series`

Mỗi phản hồi mang theo một mảng `labels` (trục thời gian, được điền số 0 trên toàn bộ phạm vi) và một mục trong `series` cho mỗi nhóm, mỗi mục chứa một mảng cho mỗi chỉ số được yêu cầu căn chỉnh theo `labels`. Các chuỗi sau `limit` không bị loại bỏ — chúng được thu gọn thành `other_bucket`, được tính bằng tổng phạm vi trừ đi chuỗi được trả về, vì vậy một biểu đồ được hiển thị luôn cộng dồn thành các con số thực của bạn; `truncated` là `true` bất cứ khi nào điều đó xảy ra.

Nguồn gốc của các con số: `sent`, `delivered`, `read`, và `replied` đến từ các bản ghi tin nhắn, chứa thông tin kênh và số gửi. `booked`, `contact_created`, và `credits_spent` đến từ luồng sự kiện, không chứa số gửi, vì vậy các chỉ số đó nằm trong nhóm `null` khi bạn nhóm theo `number`.

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `from` | Không | Bắt đầu phạm vi, `YYYY-MM-DD`. Mặc định là 30 ngày trước. |
| `to` | Không | Kết thúc phạm vi, `YYYY-MM-DD`. Mặc định là hôm nay. |
| `metrics` | Không | Danh sách phân tách bằng dấu phẩy từ `sent`, `ai_sent`, `human_sent`, `delivered`, `read`, `replied`, `booked`, `contact_created`, `credits_spent`. Mặc định là `sent,replied`. Một chỉ số không xác định sẽ trả về `400`. |
| `group_by` | Không | Danh sách phân tách bằng dấu phẩy tối đa hai chiều từ `date`, `campaign`, `channel`, `agent`, `number`. `date` được chấp nhận nhưng không có tác dụng — mọi phản hồi đã mang theo trục thời gian. Bỏ qua để có một chuỗi duy nhất trên toàn tài khoản. |
| `granularity` | Không | `day` (mặc định), `week`, hoặc `month`. Các nhóm tuần bắt đầu vào thứ Hai, nhóm tháng vào ngày 1. |
| `limit` | Không | Số lượng chuỗi cần trả về trước khi phần còn lại thu gọn thành `other_bucket`, 1–50. Mặc định là 12. |
| `campaign_id` | Không | Chỉ đếm hoạt động thuộc về chiến dịch này. Kế thừa; ưu tiên `agent_id`. |
| `agent_id` | Không | Chỉ đếm hoạt động thuộc về AI Agent này. |
| `channel` | Không | Chỉ đếm hoạt động trên kênh này, ví dụ `whatsapp`. |

Phạm vi ngày của endpoint này bị giới hạn ở **92 ngày** (chặt chẽ hơn giới hạn 366 ngày được sử dụng ở nơi khác trên trang này).

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/series?from=2026-05-01&to=2026-05-31&metrics=sent,replied,booked&group_by=campaign,channel&limit=10&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({
  from: "2026-05-01",
  to: "2026-05-31",
  metrics: "sent,replied,booked",
  group_by: "campaign,channel",
  limit: "10",
});
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/series?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/series",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={
        "from": "2026-05-01",
        "to": "2026-05-31",
        "metrics": "sent,replied,booked",
        "group_by": "campaign,channel",
        "limit": 10,
    },
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "granularity": "day",
  "labels": ["2026-05-01", "2026-05-02"],
  "group_by": ["campaign", "channel"],
  "metrics": ["sent", "replied", "booked"],
  "series": [
    {
      "key": {
        "campaign_id": "campaign123",
        "campaign_name": "Spring Promo",
        "channel": "whatsapp"
      },
      "total": 812,
      "metrics": {
        "sent": [40, 35],
        "replied": [12, 9],
        "booked": [2, 1]
      }
    }
  ],
  "other_bucket": {
    "series_count": 6,
    "total": 340,
    "metrics": {
      "sent": [18, 20],
      "replied": [5, 6],
      "booked": [0, 1]
    }
  },
  "truncated": true
}
```

**Ghi chú trường:**

- `key` — danh tính của một chuỗi. Chỉ các khóa cho các chiều `group_by` được yêu cầu mới hiện diện; một chiều có giá trị không xác định cho một hàng (một tin nhắn không có chiến dịch, một sự kiện không có kênh) sẽ trả về là `null` thay vì bị loại bỏ, để các chuỗi vẫn cộng dồn thành tổng số.
- `other_bucket` — `null` khi không có gì bị thu gọn.
- Endpoint này trả về `503` với `"error_code": "analytics_unavailable"` khi cơ sở dữ liệu báo cáo không thể phản hồi cho tài khoản của bạn, thay vì một `200` đầy số không — một biểu đồ toàn số không sẽ bị hiểu nhầm là dữ liệu thực.

---

## Kết quả hội thoại

Trả về cách các cuộc hội thoại kết thúc trong một phạm vi ngày: số lượng mỗi ngày cho mỗi thẻ kết quả mà AI đã gán, cộng với tổng phạm vi cho các câu trả lời, lượt đặt lịch, lượt chuyển giao cho con người và các cuộc hội thoại mà AI không bao giờ phân loại.

`GET /analytics/outcomes`

Truyền `group_by=tag` để thu gọn trục thời gian và chỉ nhận tổng phạm vi theo thẻ — ở chế độ đó `labels` trống và mảng `counts` của mỗi thẻ trống, trong khi `total` vẫn được điền dữ liệu.

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `from` | Không | Bắt đầu phạm vi, `YYYY-MM-DD`. Mặc định là 30 ngày trước. |
| `to` | Không | Kết thúc phạm vi, `YYYY-MM-DD`. Mặc định là hôm nay. |
| `campaign_id` | Không | Chỉ đếm các cuộc hội thoại với các liên hệ hiện đang trong chiến dịch này. Cũ; ưu tiên `agent_id`. |
| `agent_id` | Không | Chỉ đếm các kết quả thuộc về AI Agent này. |
| `group_by` | Không | `date` (mặc định) giữ lại số lượng theo ngày; `tag` gộp thành tổng phạm vi. |

Phạm vi ngày của endpoint này được giới hạn ở **92 ngày**.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/outcomes?from=2026-05-01&to=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ from: "2026-05-01", to: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/outcomes?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/outcomes",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"from": "2026-05-01", "to": "2026-05-31"},
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "from": "2026-05-01",
  "to": "2026-05-31",
  "group_by": "date",
  "labels": ["2026-05-01", "2026-05-02"],
  "by_tag": [
    { "tag": "interested", "total": 84, "counts": [3, 5] },
    { "tag": "not_interested", "total": 40, "counts": [1, 2] },
    { "tag": null, "total": 12, "counts": [0, 1] }
  ],
  "totals": {
    "sessions": 260,
    "replied": 210,
    "booked": 35,
    "human_alerted": 18,
    "unresolved": 12
  }
}
```

**Ghi chú trường:**

- `by_tag[].tag` — `null` cho các cuộc hội thoại mà AI không bao giờ gán thẻ kết quả.
- `totals.human_alerted` — các cuộc hội thoại được chuyển giao cho con người; điều này được ghi lại trong mọi lần chuyển giao và trước đây không được hiển thị bởi bất kỳ endpoint nào.
- Cùng trạng thái `503`/`analytics_unavailable` như chuỗi Metric khi cơ sở dữ liệu báo cáo không thể phản hồi.

---

## Thông tin chi tiết từ bảng điều khiển

Trả về toàn bộ dữ liệu bảng điều khiển cho một phạm vi ngày trong một lần gọi: bản đồ nhiệt tỷ lệ phản hồi theo ngày trong tuần và giờ, bảng xếp hạng chiến dịch, khối lượng theo kênh, tổng số chính xác theo kết nối, phân tích số liệu theo ngày (toàn tài khoản, theo kênh và theo số), nguồn gốc liên hệ, thời gian phản hồi hộp thư đến và nguồn cấp hoạt động gần đây. Đây là dữ liệu báo cáo phong phú nhất trên API — nó cung cấp trực tiếp cho bảng điều khiển trong ứng dụng.

`GET /analytics/dashboard-insights`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `startDate` | Có | Bắt đầu phạm vi, `YYYY-MM-DD`. |
| `endDate` | Có | Kết thúc phạm vi, `YYYY-MM-DD`. |
| `campaignId` | Không | Chỉ bao gồm hoạt động thuộc về chiến dịch này (cũng chấp nhận `campaign_id`). Cũ; ưu tiên `agent_id`. |
| `agent_id` | Không | Chỉ bao gồm hoạt động thuộc về AI Agent này (cũng chấp nhận `agentId`). Trong phạm vi đại lý, bảng xếp hạng chiến dịch được xây dựng chỉ từ hoạt động của đại lý đó. |

Endpoint này sử dụng `startDate`/`endDate` (không phải `from`/`to`) vì nó chia sẻ cách triển khai với bảng điều khiển trong ứng dụng. Phạm vi được giới hạn ở 92 ngày và sẽ **bị cắt bớt, không bị từ chối**, khi phạm vi rộng hơn.

> **Null nghĩa là không khả dụng, không phải bằng không.** Một số khối (`numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`) được tính toán từ cơ sở dữ liệu báo cáo và trả về `null` khi nó không thể phản hồi cho tài khoản của bạn. Đừng hiển thị khối `null` dưới dạng biểu đồ trống.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/dashboard-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()
```

**Phản hồi** (đã rút gọn — dữ liệu này rất lớn; xem [Tài liệu tham khảo API](reference.md) để biết lược đồ đầy đủ)

```json
{
  "success": true,
  "data": {
    "heatmap": {
      "buckets": [
        { "weekday": 1, "hour": 9, "sent": 12, "replied": 5, "replyRate": 0.42 }
      ]
    },
    "topCampaigns": [
      { "campaignId": "campaign123", "name": "Spring Promo", "sent": 420, "replied": 180, "booked": 22, "replyRate": 0.43, "creditsSpent": 210.5 }
    ],
    "channelVolume": [
      { "channel": "whatsapp", "sent": 800, "received": 540, "lastMessageAt": "2026-05-31T14:02:11.000Z" }
    ],
    "inboxSla": { "medianFirstResponseMs": 92000, "sampleSize": 140 },
    "activityFeed": [
      { "id": "evt_1", "kind": "booked", "at": "2026-05-31T14:02:11.000Z", "contactId": "contact456", "contactName": "Jane Smith", "campaignId": "campaign123", "campaignName": "Spring Promo", "label": "Jane Smith booked an appointment" }
    ],
    "numberStats": null,
    "channelDailySeries": null,
    "metricDailyBreakdown": null,
    "contactsByCountry": null,
    "ai_human_split": null
  }
}
```

**Ghi chú trường:**

- `heatmap.buckets[].weekday` — `0` là Chủ nhật đến `6` là Thứ Bảy.
- `numberStats`, `channelDailySeries`, `metricDailyBreakdown`, `contactsByCountry`, `ai_human_split` — mỗi mục độc lập `null` khi cơ sở dữ liệu báo cáo không khả dụng cho tài khoản của bạn; mọi khối khác vẫn trả về kết quả.

---

## Thông tin chi tiết từ AI của bảng điều khiển

Trả về ba thông tin chi tiết ngắn gọn do AI viết về hoạt động nhắn tin của tài khoản trong một phạm vi ngày: một thành công, một điều cần theo dõi và một mẹo — những câu bạn có thể dán trực tiếp vào báo cáo thay vì các con số mà bạn vẫn phải tự diễn giải. Được tạo chỉ từ số liệu tin nhắn của chính tài khoản.

`GET /analytics/dashboard-ai-insights`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `startDate` | Có | Bắt đầu phạm vi, `YYYY-MM-DD`. |
| `endDate` | Có | Kết thúc phạm vi, `YYYY-MM-DD`. |

Điểm cuối này áp dụng cho toàn bộ tài khoản — nó không yêu cầu phạm vi chiến dịch hoặc tác nhân.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ startDate: "2026-05-01", endDate: "2026-05-31" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/dashboard-ai-insights",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"startDate": "2026-05-01", "endDate": "2026-05-31"},
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "data": {
    "insights": [
      { "tone": "win", "title": "Reply rate is up", "detail": "Your reply rate climbed to 43% this period, up from 36% the period before." },
      { "tone": "watch", "title": "Bookings slowed midweek", "detail": "Wednesday bookings dropped to a third of Monday's, worth a look at your Wednesday follow-up timing." },
      { "tone": "tip", "title": "Re-send to non-repliers", "detail": "212 contacts received a message but never replied — a short follow-up template often recovers 10-15% of them." }
    ]
  }
}
```

Thiếu `startDate` hoặc `endDate` sẽ trả về `400`.

---

## Dòng thời gian hoạt động của thực thể

Trả về hoạt động của một liên hệ, giao dịch hoặc tác vụ duy nhất dưới dạng một dòng thời gian, sắp xếp theo thứ tự mới nhất trước: điều gì đã xảy ra và khi nào, bao gồm tin nhắn, cuộc hẹn, ghi chú và thay đổi trạng thái. Sử dụng nó để trả lời câu hỏi "điều gì đã xảy ra với người này" mà không cần phải kết hợp nhiều điểm cuối danh sách lại với nhau.

`GET /analytics/entity-activity`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `entityType` | Có | `contact`, `deal`, hoặc `task`. |
| `entityId` | Có | ID của bản ghi mà bạn muốn lấy dòng thời gian. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/entity-activity?entityType=contact&entityId=contact456&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ entityType: "contact", entityId: "contact456" });
const res = await fetch(`https://api.youraiconnector.com/v1/analytics/entity-activity?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/analytics/entity-activity",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"entityType": "contact", "entityId": "contact456"},
)
data = res.json()
```

**Phản hồi**

```json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "evt_9",
        "kind": "appointment_booked",
        "at": "2026-05-31T14:02:11.000Z",
        "label": "Booked an appointment for June 3",
        "detail": "Consultation call, 30 minutes"
      },
      {
        "id": "evt_8",
        "kind": "message_replied",
        "at": "2026-05-31T13:58:02.000Z",
        "label": "Replied: \"Yes, that time works\""
      }
    ]
  }
}
```

Thiếu hoặc không hợp lệ `entityType`/`entityId` sẽ trả về `400`. Một thực thể không tồn tại trong tài khoản của bạn sẽ trả về `404`, vì vậy ID của các tài khoản khác không thể đoán được.

---

## Tổng hợp số lượng sự kiện (cũ)

Trả về cùng số lượng sự kiện tổng hợp như [Tóm tắt lưu lượng tin nhắn](#message-volume-summary), nhưng ở định dạng camelCase (`contactCreated` thay vì `contact_created`, `byDate` thay vì `by_date`) mà một số tích hợp cũ hơn đã sử dụng. Hãy ưu tiên `/analytics/summary` cho các tích hợp mới — điểm cuối này chỉ tồn tại để bảng điều khiển trong ứng dụng và API chia sẻ chung một triển khai.

`GET /analytics/aggregate`

| Tham số | Bắt buộc | Mô tả |
|---|---|---|
| `startDate` | Không | Bắt đầu phạm vi, ngày hoặc ngày-giờ theo chuẩn ISO. Mặc định là cùng khoảng thời gian mà `/analytics/summary` sử dụng. |
| `endDate` | Không | Kết thúc phạm vi, ngày hoặc ngày-giờ theo chuẩn ISO. |
| `campaignId` | Không | Chỉ đếm các sự kiện thuộc chiến dịch này (`campaign_id` cũng được chấp nhận). Cũ; hãy ưu tiên `agent_id`. |
| `agent_id` | Không | Chỉ đếm các sự kiện thuộc về AI Agent này (`agentId` cũng được chấp nhận). |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/analytics/aggregate?startDate=2026-05-01&endDate=2026-05-31&apiKey=YOUR_API_KEY"
```

**Phản hồi**

```json
{
  "success": true,
  "data": {
    "from": "2026-05-01",
    "to": "2026-05-31",
    "total": 1240,
    "byAnalyticType": {
      "total": 1240,
      "sent": 800,
      "delivered": 760,
      "read": 540,
      "replied": 210,
      "booked": 35,
      "contactCreated": 120,
      "creditsSpent": 412.5,
      "creditsRecharged": 500
    },
    "byDate": [
      { "date": "2026-05-01", "byAnalyticType": { "total": 40, "sent": 25, "delivered": 24, "read": 18, "replied": 7, "booked": 1, "contactCreated": 4, "creditsSpent": 13.5, "creditsRecharged": 0 } }
    ]
  }
}
```

---

## Tổng hợp tài khoản phụ của đại lý


---

## Các lỗi API Analytics

Các endpoint của Analytics trả về cấu trúc lỗi tiêu chuẩn:

```json
{
  "success": false,
  "error": "Date range too large. Maximum is 366 days."
}
```

Trên một điểm cuối phân tích, định dạng ngày không hợp lệ hoặc khoảng thời gian nằm ngoài phạm vi sẽ trả về `400`, và một `campaign_id` hoặc `agent_id` không xác định sẽ trả về `404`. Việc gửi cả `campaign_id` và `agent_id` trên một điểm cuối chỉ chấp nhận một trong hai cũng là một `400` — hãy truyền tối đa một tham số. Các điểm cuối báo cáo chỉ dành cho PG (Chuỗi chỉ số, Kết quả hội thoại, Tổng hợp đại lý) trả về `503` với `"error_code": "analytics_unavailable"` thay vì một `200` đầy số 0 khi cơ sở dữ liệu báo cáo không thể phản hồi cho tài khoản của bạn — hãy thử lại sau một thời gian ngắn. 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, hoặc đối với tổng hợp đại lý, tài khoản của bạn không phải là Agency/Dev), `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

- [Xác thực](authentication.md) — bốn cách để xác thực một yêu cầu.
- [Lỗi & Giới hạn tốc độ](errors-and-pagination.md) — các mã trạng thái và giới hạn 300 yêu cầu/phút.
- [API Chiến dịch](campaigns.md) — các chiến dịch mà những số liệu này có thể được lọc theo.
