> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pathors.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 查詢外撥活動明細

> 以游標分頁讀取單一外撥活動的通話明細，支援增量拉取

讀取單一外撥活動的每一筆派送結果——與儀表板「匯出 CSV」相同的資料，以 JSON 回傳。適合排程程式在每日撥打結束後自動拉取當日結果。

此端點為唯讀，不提供任何寫入行為。

## 請求

```bash theme={null}
GET https://api.pathors.com/v1/campaigns/{campaign_id}/dispatches
```

### 標頭

<ParamField header="Authorization" type="string" required>
  使用您的 Developer Key（`dk_...`）進行 Bearer 令牌認證。
</ParamField>

### 查詢參數

<ParamField query="status" type="string">
  以派送狀態篩選，逗號分隔（例如 `completed,failed`）。省略則不篩選。傳入無法識別的值會回傳 `400`，而非靜默回傳空結果。
</ParamField>

<ParamField query="updated_after" type="string">
  ISO 8601 時間（需帶時區位移），只回傳此時間之後有更新的紀錄。用於增量拉取。
</ParamField>

<ParamField query="cursor" type="string">
  分頁游標。請原樣回傳上一頁的 `next_cursor`，不要自行解析或組合其內容。
</ParamField>

<ParamField query="limit" type="integer">
  單頁筆數上限。預設 `1000`，最大 `5000`。
</ParamField>

### 範例

```bash theme={null}
curl -H "Authorization: Bearer dk_your_key" \
  "https://api.pathors.com/v1/campaigns/cmp_your_campaign_id/dispatches?limit=100&status=completed,failed"
```

## 回應

```json theme={null}
{
  "campaign_id": "cmp_your_campaign_id",
  "data": [
    {
      "dispatch_id": "dsp_example001",
      "session_id": "ses_example001",
      "phone_number": "+886900000000",
      "dispatch_status": "completed",
      "dispatch_failed_reason": null,
      "call_status": "userHangup",
      "duration_seconds": 96,
      "message_count": 12,
      "evaluation": "Pass",
      "created_at": "2026-08-19T02:20:00.000Z",
      "started_at": "2026-08-19T02:23:00.000Z",
      "ended_at": "2026-08-19T02:24:36.000Z",
      "updated_at": "2026-08-19T02:25:12.000Z",
      "variables": {
        "customer_intent": "interested",
        "preferred_time": "afternoon"
      }
    }
  ],
  "next_cursor": "eyJ1IjoiMjAyNi0wOC0xOVQwMjoyNToxMi4wMDBaIiwiaSI6ImRzcF9leGFtcGxlMDAxIn0",
  "has_more": true
}
```

### 欄位

| 欄位                       | 型別              | 說明                                                 |
| ------------------------ | --------------- | -------------------------------------------------- |
| `dispatch_id`            | string          | 此筆派送的識別碼，也是分頁的排序鍵之一                                |
| `session_id`             | string \| null  | 對應的通話會話。尚未撥打時為 `null`                              |
| `phone_number`           | string          | 目標號碼，E.164 格式                                      |
| `dispatch_status`        | string          | 派送狀態，見下方列舉                                         |
| `dispatch_failed_reason` | string \| null  | 派送失敗的原因，僅在 `failed` 時可能有值                          |
| `call_status`            | string \| null  | 通話結果狀態（如 `userHangup`、`userNoAnswer`）。未撥打時為 `null` |
| `duration_seconds`       | integer \| null | 通話秒數                                               |
| `message_count`          | integer \| null | 對話輪次數。未撥打時為 `null`，已撥打但無對話時為 `0`                   |
| `evaluation`             | string \| null  | 評估結果，見下方說明                                         |
| `created_at`             | string          | 此筆派送建立時間（ISO 8601，UTC）                             |
| `started_at`             | string \| null  | 通話開始時間                                             |
| `ended_at`               | string \| null  | 通話結束時間                                             |
| `updated_at`             | string          | 最後更新時間，供 `updated_after` 使用                        |
| `variables`              | object          | 動態欄位，見下方說明                                         |

### `dispatch_status` 列舉值

| 值           | 意義                                |
| ----------- | --------------------------------- |
| `pending`   | 已在名單中，尚未進入派送佇列                    |
| `queued`    | 已排入佇列，等待撥號                        |
| `running`   | 通話進行中                             |
| `completed` | 派送完成（不代表對方接聽，接聽與否看 `call_status`） |
| `failed`    | 派送失敗，原因見 `dispatch_failed_reason` |

### `evaluation`

評估結果的內容取決於該專案設定的評估準則：

* **通過／未通過型**：`"Pass"`、`"Fail"`，無法判定時為 `"Unknown"`
* **分數型**：數值的字串形式，例如 `"4.5"`
* **列舉型**：該專案自訂的列舉值字串

尚未評估或該專案未設定評估準則時為 `null`。

### `variables`

動態欄位，內容依各專案的變數管理設定而定——通話中擷取到什麼，這裡就有什麼。專案新增變數時，此欄位會自動反映，不需要 API 改版。

<Warning>
  **某個變數若該通電話沒有擷取到，該筆紀錄就不會有那個 key**，而不是給空字串。CSV 匯出因為要對齊表頭，會把所有紀錄的欄位補齊；JSON 不會。

  請以「key 可能不存在」的前提撰寫客戶端程式，例如 `record.variables.customer_intent ?? ""`，不要直接假設欄位存在。
</Warning>

當一筆紀錄完全沒有擷取結果時，`variables` 會退回該聯絡人匯入名單時帶入的原始欄位。這涵蓋兩種情況，不只一種：從未撥打的聯絡人，以及**撥打了但沒產生任何變數**的聯絡人（沒接、對方立刻掛斷）。

<Note>
  這個 fallback 與後台 CSV 匯出的行為刻意不同。CSV 的表頭只由「擷取到的變數」加上「從未撥打之聯絡人的原始欄位」組成，所以「撥了但沒擷取到」的那筆在 CSV 是空白格，在本 API 則會回傳它的原始欄位。

  兩者只在極端情況可區分：`session_id` 為 `null` 代表從未撥打，該筆的 `variables` 必定是原始欄位。若 `session_id` 有值，API 不會標示這些值來自通話擷取還是匯入名單——請當作「這個聯絡人目前最好的一組值」使用。
</Note>

## 分頁

以游標分頁，逐頁讀取直到 `has_more` 為 `false`：

```bash theme={null}
# 第一頁
curl -H "Authorization: Bearer dk_your_key" \
  "https://api.pathors.com/v1/campaigns/cmp_your_campaign_id/dispatches?limit=1000"

# 後續頁：帶入上一頁的 next_cursor
curl -H "Authorization: Bearer dk_your_key" \
  "https://api.pathors.com/v1/campaigns/cmp_your_campaign_id/dispatches?limit=1000&cursor=eyJ1IjoiMjAyNi0w..."
```

<Note>
  單頁回傳筆數可能少於 `limit`：為了控制單次回應大小，當 `variables` 內容較多時系統會提早收尾。這種情況一樣以 `has_more: true` 表示，照常帶 `next_cursor` 繼續即可——**請以 `has_more` 判斷是否還有資料，不要用「筆數是否等於 `limit`」判斷**。
</Note>

<Note>
  活動仍在撥打時，同一筆紀錄可能出現在多個分頁。分頁以 `updated_at` 排序，而撥號程式會隨通話進度改寫它，因此已經讀過的紀錄可能被推到游標之後、在後面的分頁再次回傳。**不會漏行，只會重複**。若要在活動撥打中途分頁，請**以 `dispatch_id` 去重**；撥打結束後才啟動的拉取不受影響。
</Note>

游標為不透明字串，請原樣傳回。其內容格式不屬於公開契約，可能在不影響相容性的前提下變更。

## 每日增量拉取

建議的排程用法：每日撥打結束後執行一次，以 `updated_after` 帶入上次成功拉取的時間，只取當日有更新的紀錄。

```bash theme={null}
curl -H "Authorization: Bearer dk_your_key" \
  "https://api.pathors.com/v1/campaigns/cmp_your_campaign_id/dispatches?updated_after=2026-08-19T00:00:00%2B08:00&limit=1000"
```

<Note>
  `+` 在查詢字串中需編碼為 `%2B`，否則會被解析為空白字元導致時區錯誤。
</Note>

建議以「上一次拉取到的最大 `updated_at`」作為下一次的 `updated_after`，而非以當地日期的午夜為界——通話結束後的評估寫入可能落在跨日之後。

這個水位線請再往回退一小段安全邊界（幾秒就夠），並以 `dispatch_id` 去重。`updated_after` 用的是嚴格大於（`>`），若某筆紀錄剛好寫在上一次拉取讀到的那一毫秒，之後任何一次拉取都不會再取到它。

## 錯誤

| 狀態碼 | 時機                                                                         |
| --- | -------------------------------------------------------------------------- |
| 400 | `status` 含無法識別的值、`updated_after` 非合法 ISO 8601、`cursor` 格式錯誤，或 `limit` 超出範圍 |
| 401 | 缺少或無效的 Developer Key                                                       |
| 403 | 此 Developer Key 無權存取該活動所屬的專案                                               |
| 404 | 找不到該外撥活動                                                                   |
| 500 | 內部伺服器錯誤                                                                    |

## 說明

* **權限範圍**：Developer Key 只能讀取自身有權存取之專案底下的外撥活動。跨專案存取回傳 `403`。
* **與 CSV 匯出的差異**：資料來源與欄位相同，但 API 回傳原始值而非顯示格式——`dispatch_status` 是 `completed` 而非 `Completed`，`duration_seconds` 是 `96` 而非 `1m 36s`。時間一律為 UTC 的 ISO 8601。
* **網路白名單**：請以主機名稱 `api.pathors.com` 設定允許清單。此網域位於 Cloudflare 之後，回應的 IP 屬於 Cloudflare 的 anycast 位址且會變動，**不要固定特定 IP**；若貴司政策必須以 IP 設定，請採用 [Cloudflare 公布的 IP 範圍](https://www.cloudflare.com/ips/)。
