> For the complete documentation index, see [llms.txt](https://docs.maiagent.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.maiagent.ai/api/api-reference/dui-hua-he-xun-xi.md).

# 對話與訊息

### 發送訊息 (串流) <a href="#chatbots-completions-create" id="chatbots-completions-create"></a>

POST `/api/v1/chatbots/{chatbotId}/completions/`

#### 參數

| 參數名稱        | 必填 | 類型     | 說明 |
| ----------- | -- | ------ | -- |
| `chatbotId` | ✅  | string |    |

#### 請求內容

**請求參數**

| 欄位                            | 類型                                                          | 必填 | 說明                                                                                                                                        |
| ----------------------------- | ----------------------------------------------------------- | -- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| conversation                  | string (uuid)                                               | 否  | 對話的唯一識別碼，如果為空則會建立新對話（可選）                                                                                                                  |
| message                       | object (含 9 個屬性: content, contentPayload, queryMetadata...) | 是  | 要發送的訊息內容                                                                                                                                  |
| message.content               | string                                                      | 是  | 訊息的文字內容，若有提供附件則可為空字串                                                                                                                      |
| message.contentPayload        | object                                                      | 否  | 訊息的額外內容負載，JSON 格式（可選）                                                                                                                     |
| message.queryMetadata         | object                                                      | 否  | 查詢元數據，JSON 格式（可選）                                                                                                                         |
| message.metadata              | object                                                      | 否  | 訊息的環境元數據，例如時區等資訊，JSON 格式（可選）                                                                                                              |
| message.attachments           | array\[AttachmentInput]                                     | 否  | 訊息的附件列表（可選）                                                                                                                               |
| message.toolIds               | array\[string]                                              | 否  | 本次訊息指定啟用的工具 ID 列表（可選）                                                                                                                     |
| message.clientTools           | array\[any]                                                 | 否  | 本次訊息由客戶端（如 Chrome extension）提供的工具定義列表（可選）。每筆需含 name(str)、description(str)、input\_schema(dict)。LLM 呼叫時後端不會執行，而是回傳 clientToolCall 內容並結束本回合。 |
| message.sender                | string (uuid)                                               | 否  | 發送者的 Contact ID（可選）；與 externalUser 二擇一                                                                                                    |
| message.externalUser          | object (含 4 個屬性: id, name, email...)                        | 否  | 以呼叫端系統的使用者身分提問（可選）：MaiAgent 依外部使用者 ID 找到或建立聯絡人，對話記在該聯絡人名下；與 sender 二擇一，兩者同時提供回 400                                                        |
| message.externalUser.id       | string                                                      | 是  | 呼叫端系統自己的使用者 ID（必填，原字串完全比對、區分大小寫，空字串或全空白回 400）。MaiAgent 依（組織, 外部使用者 ID）找到或建立聯絡人；同一組織有多個外部系統時建議加系統前綴，例如 projects:usr\_123                   |
| message.externalUser.name     | string                                                      | 否  | 聯絡人名稱（可選）；有帶就更新，沒帶（或帶 null／空字串）不變；新建時未帶則以外部使用者 ID 為名稱                                                                                     |
| message.externalUser.email    | object                                                      | 否  | 聯絡人 Email（可選）；有帶就更新，沒帶（或帶 null／空字串）不變；非空但格式不合法回 400                                                                                       |
| message.externalUser.metadata | object                                                      | 否  | 聯絡人自訂資訊（可選），格式同聯絡人 API 的 metadata；有帶就整份覆蓋，沒帶（或帶 null）不變                                                                                   |
| isStreaming                   | boolean                                                     | 否  | 是否使用串流模式回應，預設為 false（可選）                                                                                                                  |
| waitForAttachments            | boolean                                                     | 否  | 是否等待附件處理完成後再進入 agent workflow，預設為 true（可選）                                                                                                |

**請求結構範例**

```typescript
{
  "conversation"?: string (uuid) // 對話的唯一識別碼，如果為空則會建立新對話（可選） (非必填)
  "message":  // 要發送的訊息內容
  {
    "content": string // 訊息的文字內容，若有提供附件則可為空字串
    "contentPayload"?: object // 訊息的額外內容負載，JSON 格式（可選） (非必填)
    "queryMetadata"?: object // 查詢元數據，JSON 格式（可選） (非必填)
    "metadata"?: object // 訊息的環境元數據，例如時區等資訊，JSON 格式（可選） (非必填)
    "attachments"?: [ // 訊息的附件列表（可選） (非必填)
      {
        "id": string (uuid) // 附件的唯一識別碼
        "type":  // 附件類型，可選值：image（圖片）、video（影片，開發中，尚未支援）、audio（音訊）、sticker（貼圖，開發中，尚未支援）、other（其他）

* `image` - Image
* `video` - Video
* `audio` - Audio
* `sticker` - Sticker
* `other` - Other
        {
        }
        "filename": string // 附件的檔案名稱
        "file": string (uri) // 附件檔案的 URL 位址
      }
    ]
    "toolIds"?: [ // 本次訊息指定啟用的工具 ID 列表（可選） (非必填)
      string (uuid)
    ]
    "clientTools"?: [ // 本次訊息由客戶端（如 Chrome extension）提供的工具定義列表（可選）。每筆需含 name(str)、description(str)、input_schema(dict)。LLM 呼叫時後端不會執行，而是回傳 clientToolCall 內容並結束本回合。 (非必填)
      object
    ]
    "sender"?: string (uuid) // 發送者的 Contact ID（可選）；與 externalUser 二擇一 (非必填)
    "externalUser"?:  // 以呼叫端系統的使用者身分提問（可選）：MaiAgent 依外部使用者 ID 找到或建立聯絡人，對話記在該聯絡人名下；與 sender 二擇一，兩者同時提供回 400 (非必填)
    {
      "id": string // 呼叫端系統自己的使用者 ID（必填，原字串完全比對、區分大小寫，空字串或全空白回 400）。MaiAgent 依（組織, 外部使用者 ID）找到或建立聯絡人；同一組織有多個外部系統時建議加系統前綴，例如 projects:usr_123
      "name"?: string // 聯絡人名稱（可選）；有帶就更新，沒帶（或帶 null／空字串）不變；新建時未帶則以外部使用者 ID 為名稱 (非必填)
      "email"?: // 可能有不同的類型 (非必填)
      string (email) // 聯絡人 Email（可選）；有帶就更新，沒帶（或帶 null／空字串）不變；非空但格式不合法回 400 (非必填)
      "metadata"?: object // 聯絡人自訂資訊（可選），格式同聯絡人 API 的 metadata；有帶就整份覆蓋，沒帶（或帶 null）不變 (非必填)
    }
  }
  "isStreaming"?: boolean // 是否使用串流模式回應，預設為 false（可選） (非必填)
  "waitForAttachments"?: boolean // 是否等待附件處理完成後再進入 agent workflow，預設為 true（可選） (非必填)
}
```

**請求範例值**

```json
{
  "message": {
    "content": "你好，請介紹一下你自己"
  },
  "is_streaming": true
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/chatbots/550e8400-e29b-41d4-a716-446655440000/completions/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": {
      "content": "你好，請介紹一下你自己"
    },
    "is_streaming": true
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "message": {
      "content": "你好，請介紹一下你自己"
    },
    "is_streaming": true
  };

axios.post("https://api.maiagent.ai/api/v1/chatbots/550e8400-e29b-41d4-a716-446655440000/completions/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/chatbots/550e8400-e29b-41d4-a716-446655440000/completions/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "message": {
        "content": "你好，請介紹一下你自己"
    },
    "is_streaming": True
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/chatbots/550e8400-e29b-41d4-a716-446655440000/completions/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'message' => [
                'content' => '你好，請介紹一下你自己'
            ],
            'is_streaming' => true
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明                                                                                                                                                                                                                                |
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 200 | 對話回應內容，若是串流則為事件流                                                                                                                                                                                                                  |
| 202 | Attachments are still being indexed: the body \`status\` is \`pending\_attachments\`; retry later.                                                                                                                                |
| 400 | 請求參數錯誤，可能原因包括：Contact ID 不屬於該組織 Error codes (X-Error-Code): \`contact\_not\_found\`, \`contact\_organization\_mismatch\`, \`contact\_inbox\_not\_linked\`, \`contact\_permission\_denied\`, \`message\_content\_required\`, \`... |
| 401 | Error codes (X-Error-Code): \`not\_authenticated\`, \`authentication\_failed\`.                                                                                                                                                   |
| 402 | Error codes (X-Error-Code): \`insufficient\_credits\`, \`insufficient\_quota\`, \`no\_active\_plan\`.                                                                                                                             |
| 403 | Error codes (X-Error-Code): \`permission\_denied\`.                                                                                                                                                                               |
| 404 | Error codes (X-Error-Code): \`conversation\_not\_found\`, \`not\_found\`.                                                                                                                                                         |
| 429 | Error codes (X-Error-Code): \`throttled\`.                                                                                                                                                                                        |

***

### 發送訊息 (建立) <a href="#messages-create" id="messages-create"></a>

POST `/api/v1/messages/`

#### 請求內容

**請求參數**

| 欄位                                      | 類型                                                 | 必填 | 說明                                                                                      |
| --------------------------------------- | -------------------------------------------------- | -- | --------------------------------------------------------------------------------------- |
| conversation                            | string (uuid)                                      | 是  |                                                                                         |
| type                                    | string                                             | 否  |                                                                                         |
| content                                 | string                                             | 否  |                                                                                         |
| contentPayload                          | object                                             | 否  |                                                                                         |
| attachments                             | array\[MessageAttachmentInput]                     | 否  |                                                                                         |
| canvas                                  | object                                             | 否  |                                                                                         |
| canvas.name                             | string                                             | 是  |                                                                                         |
| canvas.canvasType                       | object                                             | 是  |                                                                                         |
| canvas.title                            | string                                             | 是  |                                                                                         |
| canvas.content                          | string                                             | 是  |                                                                                         |
| slideTemplate                           | object (含 3 個屬性: slug, displayName, thumbnailUrls) | 否  |                                                                                         |
| slideTemplate.slug                      | string                                             | 是  |                                                                                         |
| slideTemplate.displayName               | string                                             | 是  |                                                                                         |
| slideTemplate.thumbnailUrls             | array\[string]                                     | 否  |                                                                                         |
| queryMetadata                           | object                                             | 否  | 查詢元資料，控制可查詢的知識範圍；詳見各端點說明                                                                |
| queryMetadata.knowledgeBases            | array\[object]                                     | 否  | 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制                                                  |
| queryMetadata.labelRelations            | object                                             | 否  | 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） |
| queryMetadata.labelRelations.operator   | string (enum: AND, OR)                             | 是  | 標籤條件的組合方式                                                                               |
| queryMetadata.labelRelations.conditions | array\[any]                                        | 否  | 標籤條件清單，支援巢狀 operator/conditions 組合                                                      |
| metadata                                | object                                             | 否  | Message metadata, such as timezone and other environment information                    |
| broadcast                               | boolean                                            | 否  |                                                                                         |
| skipCopilotTrigger                      | boolean                                            | 否  |                                                                                         |
| suggestedForId                          | string (uuid)                                      | 否  |                                                                                         |
| skillIds                                | array\[string]                                     | 否  | Per-message selected skill IDs from the WebChat client (camelCase: skillIds).           |
| toolIds                                 | array\[string]                                     | 否  | Per-message selected tool IDs from the WebChat client (camelCase: toolIds).             |
| templateId                              | string (uuid)                                      | 否  | Document/sheet template ID for file-level compilation (camelCase: templateId).          |

**請求結構範例**

```typescript
{
  "conversation": string (uuid)
  "type"?: string // 非必填
  "content"?: string // 非必填
  "contentPayload"?: object // 非必填
  "attachments"?: [ // 非必填
    {
      "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
      "type"?:  // 非必填
      {
      }
      "filename": string
      "file": string (uri)
      "conversation"?: string (uuid) // 非必填
    }
  ]
  "canvas"?: { // 非必填
  {
    "name": string
    "canvasType": 
    {
    }
    "title": string
    "content": string
  }
  }
  "slideTemplate"?:  // 非必填
  {
    "slug": string
    "displayName": string
    "thumbnailUrls"?: [ // 非必填
      string
    ]
  }
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
  "broadcast"?: boolean // 非必填
  "skipCopilotTrigger"?: boolean // 非必填
  "suggestedForId"?: string (uuid) // 非必填
  "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
    string (uuid)
  ]
  "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
    string (uuid)
  ]
  "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
}
```

**請求範例值**

```json
{
  "conversation": "c96a0fb9-d106-4b16-8706-3906533bafa2",
  "sender": {
    "id": 2.992461161002561e+38,
    "name": "jessiekuo",
    "avatar": "https://media-dev.maiagent.ai/static/images/default-user-avatar.png"
  },
  "type": "incoming",
  "content": "這是一條測試訊息",
  "contentPayload": {
    "content": "這是一條測試訊息",
    "items": [
      {
        "type": "text",
        "text": "這是一條測試訊息",
        "startTimestamp": null,
        "citations": []
      }
    ],
    "metadata": null
  },
  "feedback": null,
  "createdAt": "1748314926000",
  "attachments": [],
  "citations": [],
  "citationNodes": [],
  "canvas": {
    "id": "034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd",
    "name": "system-architecture-diagram",
    "canvasType": "markdown",
    "title": "系統架構圖",
    "content": "~~~mermaid\ngraph TD\n    A[用戶] --> B[前端界面]\n    B --> C[API層]\n    C --> D[數據庫]\n~~~",
    "createdAt": "1748314926000"
  }
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/messages/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation": "c96a0fb9-d106-4b16-8706-3906533bafa2",
    "sender": {
      "id": 2.992461161002561e+38,
      "name": "jessiekuo",
      "avatar": "https://media-dev.maiagent.ai/static/images/default-user-avatar.png"
    },
    "type": "incoming",
    "content": "這是一條測試訊息",
    "contentPayload": {
      "content": "這是一條測試訊息",
      "items": [
        {
          "type": "text",
          "text": "這是一條測試訊息",
          "startTimestamp": null,
          "citations": []
        }
      ],
      "metadata": null
    },
    "feedback": null,
    "createdAt": "1748314926000",
    "attachments": [],
    "citations": [],
    "citationNodes": [],
    "canvas": {
      "id": "034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd",
      "name": "system-architecture-diagram",
      "canvasType": "markdown",
      "title": "系統架構圖",
      "content": "~~~mermaid\ngraph TD\n    A[用戶] --> B[前端界面]\n    B --> C[API層]\n    C --> D[數據庫]\n~~~",
      "createdAt": "1748314926000"
    }
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "conversation": "c96a0fb9-d106-4b16-8706-3906533bafa2",
    "sender": {
      "id": 2.992461161002561e+38,
      "name": "jessiekuo",
      "avatar": "https://media-dev.maiagent.ai/static/images/default-user-avatar.png"
    },
    "type": "incoming",
    "content": "這是一條測試訊息",
    "contentPayload": {
      "content": "這是一條測試訊息",
      "items": [
        {
          "type": "text",
          "text": "這是一條測試訊息",
          "startTimestamp": null,
          "citations": []
        }
      ],
      "metadata": null
    },
    "feedback": null,
    "createdAt": "1748314926000",
    "attachments": [],
    "citations": [],
    "citationNodes": [],
    "canvas": {
      "id": "034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd",
      "name": "system-architecture-diagram",
      "canvasType": "markdown",
      "title": "系統架構圖",
      "content": "~~~mermaid\ngraph TD\n    A[用戶] --> B[前端界面]\n    B --> C[API層]\n    C --> D[數據庫]\n~~~",
      "createdAt": "1748314926000"
    }
  };

axios.post("https://api.maiagent.ai/api/v1/messages/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "conversation": "c96a0fb9-d106-4b16-8706-3906533bafa2",
    "sender": {
        "id": 2.992461161002561e+38,
        "name": "jessiekuo",
        "avatar": "https://media-dev.maiagent.ai/static/images/default-user-avatar.png"
    },
    "type": "incoming",
    "content": "這是一條測試訊息",
    "contentPayload": {
        "content": "這是一條測試訊息",
        "items": [
            {
                "type": "text",
                "text": "這是一條測試訊息",
                "startTimestamp": None,
                "citations": []
            }
        ],
        "metadata": None
    },
    "feedback": None,
    "createdAt": "1748314926000",
    "attachments": [],
    "citations": [],
    "citationNodes": [],
    "canvas": {
        "id": "034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd",
        "name": "system-architecture-diagram",
        "canvasType": "markdown",
        "title": "系統架構圖",
        "content": "~~~mermaid\ngraph TD\n    A[用戶] --> B[前端界面]\n    B --> C[API層]\n    C --> D[數據庫]\n~~~",
        "createdAt": "1748314926000"
    }
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/messages/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'conversation' => 'c96a0fb9-d106-4b16-8706-3906533bafa2',
            'sender' => [
                'id' => 2.992461161002561e+38,
                'name' => 'jessiekuo',
                'avatar' => 'https://media-dev.maiagent.ai/static/images/default-user-avatar.png'
            ],
            'type' => 'incoming',
            'content' => '這是一條測試訊息',
            'contentPayload' => [
                'content' => '這是一條測試訊息',
                'items' => [
                    [
                        'type' => 'text',
                        'text' => '這是一條測試訊息',
                        'startTimestamp' => null,
                        'citations' => []
                    ]
                ],
                'metadata' => null
            ],
            'feedback' => null,
            'createdAt' => '1748314926000',
            'attachments' => [],
            'citations' => [],
            'citationNodes' => [],
            'canvas' => [
                'id' => '034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd',
                'name' => 'system-architecture-diagram',
                'canvasType' => 'markdown',
                'title' => '系統架構圖',
                'content' => '~~~mermaid
graph TD
    A[用戶] --> B[前端界面]
    B --> C[API層]
    C --> D[數據庫]
~~~',
                'createdAt' => '1748314926000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "conversation": string (uuid)
  "sender": 
  {
    "id": string (uuid)
    "name": string
    "avatar": string
    "email"?: string (email) // 非必填
    "phoneNumber"?: string // 非必填
  }
  "type"?: string // 非必填
  "content"?: string // 非必填
  "contentPayload"?: object // 非必填
  "feedback": 
  {
    "id": string (uuid)
    "type": 
    {
    }
    "suggestion"?: string // 非必填
    "updatedAt": string (timestamp)
  }
  "createdAt": string (timestamp)
  "attachments"?: [ // 非必填
    {
      "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
      "type"?:  // 非必填
      {
      }
      "filename": string
      "file": string (uri)
      "expiresAt": string // ISO datetime when this attachment will be auto-deleted.

For conversation-bound attachments: conversation.last_message_created_at + retention_days.
For attachments without a conversation: created_at + retention_days.
Returns None when cleanup is disabled (effective_from not set).
      "conversation"?: string (uuid) // 非必填
    }
  ]
  "citations": [
    {
      "id": string (uuid)
      "filename": string // 檔案名稱
      "file": string (uri) // 要上傳的檔案
      "fileType": string
      "knowledgeBase"?:  // 非必填
      {
        "id": string (uuid)
        "name": string
      }
      "size": integer // File size in bytes
      "status": 
      {
      }
      "parser": 
      {
        "id": string (uuid)
        "name": string
        "provider": 
        {
        }
        "isTimestampSttProvider": boolean
      }
      "labels"?: [ // 非必填
        {
          "id": string (uuid)
          "name": string
        }
      ]
      "rawUserDefineMetadata"?: object // 非必填
      "speakerLabels": [
        {
          "id": string (uuid)
          "originalLabel": string // Original speaker label from diarization (e.g., SPEAKER_00)
          "customName"?: string // User-defined speaker name (e.g., John) (非必填)
          "displayName": string
        }
      ]
      "vectorStorageSize": integer // Size of vectors for this file in Elasticsearch (bytes)
      "chunksCount": integer // Number of chunks/nodes generated from this file
      "waitingTime": number (double)
      "processingTime": number (double)
      "processingTimeDetails": object
      "ocrStatus": string // 掃描頁 OCR 結果：done、skipped、partial、off；解析前或舊檔案為 null
      "ocrSkippedReason": string // 掃描頁沒做 OCR 的原因：no_azure_settings、azure_unavailable、insufficient_credits、transient_error、time_budget、disabled；有做完時為 null
      "previewUrl": string // 簡報（pptx/ppt）回傳可預覽的 pdf 衍生檔 URL（前端用 PDF 預覽器顯示）；其餘為 None。

用與 `file` 欄位相同的 CustomizedFileFieldSerializer 產 URL，確保格式一致（含各
storage provider 的 presign/host 規則）。不可用 get_absolute_url()——它產出的 URL 格式錯誤。
      "createdAt": string (timestamp)
    }
  ]
  "citationNodes": [
    {
      "chatbotTextNode": {
      {
        "id": string (uuid)
        "charactersCount": integer
        "hitsCount": integer
        "text": string
        "updatedAt": string (timestamp)
        "filename": string
        "chatbotFile": object // 返回 ChatbotFile 的完整資訊，包含檔案 URL 和類型，以支援前端圖片預覽
        "knowledgeBaseFile": object // 與 get_chatbot_file 相同，提供向後兼容
        "pageNumber": integer // Backward-compatible alias of ``page_start``.
        "pageStart": integer
        "pageEnd": integer
        "citationTitle": string // Source title shown on the inline citation hover card.
        "citationDescription": string // Source description shown on the inline citation hover card.
        "citationQuote": string // Quoted text snippet shown on the inline citation hover card.
        "hasImage": boolean // 判斷是否包含圖片（檢查檔案類型或 text 中的 Markdown 圖片）
        "imageUrl": string // 提取圖片 URL（優先使用檔案 URL，否則從 Markdown 提取）
        "displayText": string // 返回移除圖片 Markdown 標記的完整文字
        "displayTitle": string // 返回顯示標題（fallback: citation_title -> filename）
        "highlightedText": string // Return text with matched terms wrapped in ``<mark>`` tags.

Priority:
1. ES/OpenSearch native highlight (set by retrieve_api via ``_es_highlighted_text``)
2. Python regex fallback (keyword-based, works for all backends)
        "labels": [
          {
            "id": string (uuid)
            "name": string
          }
        ]
        "rawUserDefineMetadata"?: object // Metadata keys and values defined by the user. (非必填)
        "metadataEnabledForSearch": object // Map each user-defined metadata key on this node to whether it was sent into the LLM.

A key reaches the LLM only when its ``MetadataKey.enabled_for_search`` is True *and*
the node carries a value for it. Since this maps over ``raw_user_define_metadata``
(the keys the cited-documents block displays, all of which have a value),
``enabled_for_search`` alone decides the flag. The source of truth is the node's
knowledge base ``MetadataKey`` current setting, matching the AI Search indicator.
        "startCharIdx": integer
        "endCharIdx": integer
      }
      }
      "score"?: number (double) // 非必填
      "displayScore": integer
      "citationNumber"?: integer // Citation number matching the [1], [2] markers in the reply content (非必填)
      "highlightedText"?: string // ES/OpenSearch highlight result with <mark> tags (非必填)
    }
  ]
  "canvas"?: { // 非必填
  {
    "id": string (uuid)
    "name": string
    "canvasType": 
    {
    }
    "title": string
    "content": string
    "createdAt": string (timestamp)
  }
  }
  "slideTemplate"?:  // 非必填
  {
    "slug": string
    "displayName": string
    "thumbnailUrls"?: [ // 非必填
      string
    ]
  }
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
  "recordId": string // 返回 Message 對應的 ChatbotRecord ID

Note:
    對於未儲存的 Message（如 streaming 中的虛擬 Message），直接返回 None，
    避免觸發 OneToOneField reverse relation 的 DB 查詢（N+1 問題）。
  "broadcast"?: boolean // 非必填
  "skipCopilotTrigger"?: boolean // 非必填
  "activeRevisionNumber": integer
  "revisions": [
    {
      "id": string (uuid)
      "revisionNumber": integer
      "content": string
      "contentPayload": object
      "isActive": boolean
      "createdAt": string (timestamp)
    }
  ]
  "suggestedForId"?: string (uuid) // 非必填
  "suggestionStatus": string
  "suggestionTriggerSource": string
  "suggestionError": string
  "retryCount": integer // How many times the LLM call was auto-retried during this message generation. Currently only Bedrock first-chunk stall triggers retry (max 1). Detailed per-attempt records live in metadata["retry_attempts"].
  "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
    string (uuid)
  ]
  "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
    string (uuid)
  ]
  "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
  "videoGeneration": object // Return the latest GeneratedVideo state for FE reload recovery;
``errorMessage`` is blank to match the socket emit (raw value stays on the DB row).
  "isGreeting": boolean // Whether this message is a greeting message.
}
```

**回應範例值**

```json
{
  "conversation": "c96a0fb9-d106-4b16-8706-3906533bafa2",
  "sender": {
    "id": 2.992461161002561e+38,
    "name": "jessiekuo",
    "avatar": "https://media-dev.maiagent.ai/static/images/default-user-avatar.png"
  },
  "type": "incoming",
  "content": "這是一條測試訊息",
  "contentPayload": {
    "content": "這是一條測試訊息",
    "items": [
      {
        "type": "text",
        "text": "這是一條測試訊息",
        "startTimestamp": null,
        "citations": []
      }
    ],
    "metadata": null
  },
  "feedback": null,
  "createdAt": "1748314926000",
  "attachments": [],
  "citations": [],
  "citationNodes": [],
  "canvas": {
    "id": "034eecd7-e0f4-46e9-88cb-4fefdb5b7ddd",
    "name": "system-architecture-diagram",
    "canvasType": "markdown",
    "title": "系統架構圖",
    "content": "~~~mermaid\ngraph TD\n    A[用戶] --> B[前端界面]\n    B --> C[API層]\n    C --> D[數據庫]\n~~~",
    "createdAt": "1748314926000"
  }
}
```

***

### 發送主動訊息 <a href="#messages-outgoing-create" id="messages-outgoing-create"></a>

POST `/api/v1/messages/outgoing/`

#### 請求內容

**請求參數**

| 欄位                                      | 類型                                                 | 必填 | 說明                                                                                      |
| --------------------------------------- | -------------------------------------------------- | -- | --------------------------------------------------------------------------------------- |
| conversation                            | string (uuid)                                      | 是  |                                                                                         |
| type                                    | string                                             | 否  |                                                                                         |
| content                                 | string                                             | 否  |                                                                                         |
| contentPayload                          | object                                             | 否  |                                                                                         |
| attachments                             | array\[MessageAttachmentInput]                     | 否  |                                                                                         |
| canvas                                  | object                                             | 否  |                                                                                         |
| canvas.name                             | string                                             | 是  |                                                                                         |
| canvas.canvasType                       | object                                             | 是  |                                                                                         |
| canvas.title                            | string                                             | 是  |                                                                                         |
| canvas.content                          | string                                             | 是  |                                                                                         |
| slideTemplate                           | object (含 3 個屬性: slug, displayName, thumbnailUrls) | 否  |                                                                                         |
| slideTemplate.slug                      | string                                             | 是  |                                                                                         |
| slideTemplate.displayName               | string                                             | 是  |                                                                                         |
| slideTemplate.thumbnailUrls             | array\[string]                                     | 否  |                                                                                         |
| queryMetadata                           | object                                             | 否  | 查詢元資料，控制可查詢的知識範圍；詳見各端點說明                                                                |
| queryMetadata.knowledgeBases            | array\[object]                                     | 否  | 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制                                                  |
| queryMetadata.labelRelations            | object                                             | 否  | 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） |
| queryMetadata.labelRelations.operator   | string (enum: AND, OR)                             | 是  | 標籤條件的組合方式                                                                               |
| queryMetadata.labelRelations.conditions | array\[any]                                        | 否  | 標籤條件清單，支援巢狀 operator/conditions 組合                                                      |
| metadata                                | object                                             | 否  | Message metadata, such as timezone and other environment information                    |
| broadcast                               | boolean                                            | 否  |                                                                                         |
| skipCopilotTrigger                      | boolean                                            | 否  |                                                                                         |
| suggestedForId                          | string (uuid)                                      | 否  |                                                                                         |
| skillIds                                | array\[string]                                     | 否  | Per-message selected skill IDs from the WebChat client (camelCase: skillIds).           |
| toolIds                                 | array\[string]                                     | 否  | Per-message selected tool IDs from the WebChat client (camelCase: toolIds).             |
| templateId                              | string (uuid)                                      | 否  | Document/sheet template ID for file-level compilation (camelCase: templateId).          |

**請求結構範例**

```typescript
{
  "conversation": string (uuid)
  "type"?: string // 非必填
  "content"?: string // 非必填
  "contentPayload"?: object // 非必填
  "attachments"?: [ // 非必填
    {
      "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
      "type"?:  // 非必填
      {
      }
      "filename": string
      "file": string (uri)
      "conversation"?: string (uuid) // 非必填
    }
  ]
  "canvas"?: { // 非必填
  {
    "name": string
    "canvasType": 
    {
    }
    "title": string
    "content": string
  }
  }
  "slideTemplate"?:  // 非必填
  {
    "slug": string
    "displayName": string
    "thumbnailUrls"?: [ // 非必填
      string
    ]
  }
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
  "broadcast"?: boolean // 非必填
  "skipCopilotTrigger"?: boolean // 非必填
  "suggestedForId"?: string (uuid) // 非必填
  "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
    string (uuid)
  ]
  "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
    string (uuid)
  ]
  "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
}
```

**請求範例值**

```json
{
  "conversation": "550e8400-e29b-41d4-a716-446655440000",
  "type": "範例字串",
  "content": "您好！我想了解產品資訊。",
  "contentPayload": null,
  "attachments": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "type": {},
      "filename": "document.pdf",
      "file": "https://example.com/file.jpg",
      "conversation": "550e8400-e29b-41d4-a716-446655440000"
    }
  ],
  "canvas": {
    "name": "範例名稱",
    "canvasType": {},
    "title": "範例名稱",
    "content": "您好！我想了解產品資訊。"
  },
  "slideTemplate": {
    "slug": "範例字串",
    "displayName": "範例字串",
    "thumbnailUrls": [
      "範例字串"
    ]
  },
  "queryMetadata": {
    "knowledgeBases": [
      {
        "knowledgeBaseId": "550e8400-e29b-41d4-a716-446655440000",
        "chatbotFileIds": [
          "550e8400-e29b-41d4-a716-446655440000"
        ],
        "knowledgeBaseFileIds": [
          "550e8400-e29b-41d4-a716-446655440000"
        ],
        "faqIds": [
          "550e8400-e29b-41d4-a716-446655440000"
        ],
        "hasUserSelectedAll": true
      }
    ],
    "labelRelations": {
      "operator": "AND",
      "conditions": [
        null
      ]
    }
  },
  "metadata": null,
  "broadcast": true,
  "skipCopilotTrigger": true,
  "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
  "skillIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "toolIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "templateId": "550e8400-e29b-41d4-a716-446655440000"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/messages/outgoing/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation": "550e8400-e29b-41d4-a716-446655440000",
    "type": "範例字串",
    "content": "您好！我想了解產品資訊。",
    "contentPayload": null,
    "attachments": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": {},
        "filename": "document.pdf",
        "file": "https://example.com/file.jpg",
        "conversation": "550e8400-e29b-41d4-a716-446655440000"
      }
    ],
    "canvas": {
      "name": "範例名稱",
      "canvasType": {},
      "title": "範例名稱",
      "content": "您好！我想了解產品資訊。"
    },
    "slideTemplate": {
      "slug": "範例字串",
      "displayName": "範例字串",
      "thumbnailUrls": [
        "範例字串"
      ]
    },
    "queryMetadata": {
      "knowledgeBases": [
        {
          "knowledgeBaseId": "550e8400-e29b-41d4-a716-446655440000",
          "chatbotFileIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "knowledgeBaseFileIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "faqIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "hasUserSelectedAll": true
        }
      ],
      "labelRelations": {
        "operator": "AND",
        "conditions": [
          null
        ]
      }
    },
    "metadata": null,
    "broadcast": true,
    "skipCopilotTrigger": true,
    "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
    "skillIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "toolIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "templateId": "550e8400-e29b-41d4-a716-446655440000"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "conversation": "550e8400-e29b-41d4-a716-446655440000",
    "type": "範例字串",
    "content": "您好！我想了解產品資訊。",
    "contentPayload": null,
    "attachments": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": {},
        "filename": "document.pdf",
        "file": "https://example.com/file.jpg",
        "conversation": "550e8400-e29b-41d4-a716-446655440000"
      }
    ],
    "canvas": {
      "name": "範例名稱",
      "canvasType": {},
      "title": "範例名稱",
      "content": "您好！我想了解產品資訊。"
    },
    "slideTemplate": {
      "slug": "範例字串",
      "displayName": "範例字串",
      "thumbnailUrls": [
        "範例字串"
      ]
    },
    "queryMetadata": {
      "knowledgeBases": [
        {
          "knowledgeBaseId": "550e8400-e29b-41d4-a716-446655440000",
          "chatbotFileIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "knowledgeBaseFileIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "faqIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "hasUserSelectedAll": true
        }
      ],
      "labelRelations": {
        "operator": "AND",
        "conditions": [
          null
        ]
      }
    },
    "metadata": null,
    "broadcast": true,
    "skipCopilotTrigger": true,
    "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
    "skillIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "toolIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "templateId": "550e8400-e29b-41d4-a716-446655440000"
  };

axios.post("https://api.maiagent.ai/api/v1/messages/outgoing/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/outgoing/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "conversation": "550e8400-e29b-41d4-a716-446655440000",
    "type": "範例字串",
    "content": "您好！我想了解產品資訊。",
    "contentPayload": None,
    "attachments": [
        {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "type": {},
            "filename": "document.pdf",
            "file": "https://example.com/file.jpg",
            "conversation": "550e8400-e29b-41d4-a716-446655440000"
        }
    ],
    "canvas": {
        "name": "範例名稱",
        "canvasType": {},
        "title": "範例名稱",
        "content": "您好！我想了解產品資訊。"
    },
    "slideTemplate": {
        "slug": "範例字串",
        "displayName": "範例字串",
        "thumbnailUrls": [
            "範例字串"
        ]
    },
    "queryMetadata": {
        "knowledgeBases": [
            {
                "knowledgeBaseId": "550e8400-e29b-41d4-a716-446655440000",
                "chatbotFileIds": [
                    "550e8400-e29b-41d4-a716-446655440000"
                ],
                "knowledgeBaseFileIds": [
                    "550e8400-e29b-41d4-a716-446655440000"
                ],
                "faqIds": [
                    "550e8400-e29b-41d4-a716-446655440000"
                ],
                "hasUserSelectedAll": True
            }
        ],
        "labelRelations": {
            "operator": "AND",
            "conditions": [
                None
            ]
        }
    },
    "metadata": None,
    "broadcast": True,
    "skipCopilotTrigger": True,
    "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
    "skillIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "toolIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "templateId": "550e8400-e29b-41d4-a716-446655440000"
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/messages/outgoing/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'conversation' => '550e8400-e29b-41d4-a716-446655440000',
            'type' => '範例字串',
            'content' => '您好！我想了解產品資訊。',
            'contentPayload' => null,
            'attachments' => [
                [
                    'id' => '550e8400-e29b-41d4-a716-446655440000',
                    'type' => new \stdClass(),
                    'filename' => 'document.pdf',
                    'file' => 'https://example.com/file.jpg',
                    'conversation' => '550e8400-e29b-41d4-a716-446655440000'
                ]
            ],
            'canvas' => [
                'name' => '範例名稱',
                'canvasType' => new \stdClass(),
                'title' => '範例名稱',
                'content' => '您好！我想了解產品資訊。'
            ],
            'slideTemplate' => [
                'slug' => '範例字串',
                'displayName' => '範例字串',
                'thumbnailUrls' => [
                    '範例字串'
                ]
            ],
            'queryMetadata' => [
                'knowledgeBases' => [
                    [
                        'knowledgeBaseId' => '550e8400-e29b-41d4-a716-446655440000',
                        'chatbotFileIds' => [
                            '550e8400-e29b-41d4-a716-446655440000'
                        ],
                        'knowledgeBaseFileIds' => [
                            '550e8400-e29b-41d4-a716-446655440000'
                        ],
                        'faqIds' => [
                            '550e8400-e29b-41d4-a716-446655440000'
                        ],
                        'hasUserSelectedAll' => true
                    ]
                ],
                'labelRelations' => [
                    'operator' => 'AND',
                    'conditions' => [
                        null
                    ]
                ]
            ],
            'metadata' => null,
            'broadcast' => true,
            'skipCopilotTrigger' => true,
            'suggestedForId' => '550e8400-e29b-41d4-a716-446655440000',
            'skillIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'toolIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'templateId' => '550e8400-e29b-41d4-a716-446655440000'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "conversation": string (uuid)
  "sender": 
  {
    "id": string (uuid)
    "name": string
    "avatar": string
    "email"?: string (email) // 非必填
    "phoneNumber"?: string // 非必填
  }
  "type"?: string // 非必填
  "content"?: string // 非必填
  "contentPayload"?: object // 非必填
  "feedback": 
  {
    "id": string (uuid)
    "type": 
    {
    }
    "suggestion"?: string // 非必填
    "updatedAt": string (timestamp)
  }
  "createdAt": string (timestamp)
  "attachments"?: [ // 非必填
    {
      "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
      "type"?:  // 非必填
      {
      }
      "filename": string
      "file": string (uri)
      "expiresAt": string // ISO datetime when this attachment will be auto-deleted.

For conversation-bound attachments: conversation.last_message_created_at + retention_days.
For attachments without a conversation: created_at + retention_days.
Returns None when cleanup is disabled (effective_from not set).
      "conversation"?: string (uuid) // 非必填
    }
  ]
  "citations": [
    {
      "id": string (uuid)
      "filename": string // 檔案名稱
      "file": string (uri) // 要上傳的檔案
      "fileType": string
      "knowledgeBase"?:  // 非必填
      {
        "id": string (uuid)
        "name": string
      }
      "size": integer // File size in bytes
      "status": 
      {
      }
      "parser": 
      {
        "id": string (uuid)
        "name": string
        "provider": 
        {
        }
        "isTimestampSttProvider": boolean
      }
      "labels"?: [ // 非必填
        {
          "id": string (uuid)
          "name": string
        }
      ]
      "rawUserDefineMetadata"?: object // 非必填
      "speakerLabels": [
        {
          "id": string (uuid)
          "originalLabel": string // Original speaker label from diarization (e.g., SPEAKER_00)
          "customName"?: string // User-defined speaker name (e.g., John) (非必填)
          "displayName": string
        }
      ]
      "vectorStorageSize": integer // Size of vectors for this file in Elasticsearch (bytes)
      "chunksCount": integer // Number of chunks/nodes generated from this file
      "waitingTime": number (double)
      "processingTime": number (double)
      "processingTimeDetails": object
      "ocrStatus": string // 掃描頁 OCR 結果：done、skipped、partial、off；解析前或舊檔案為 null
      "ocrSkippedReason": string // 掃描頁沒做 OCR 的原因：no_azure_settings、azure_unavailable、insufficient_credits、transient_error、time_budget、disabled；有做完時為 null
      "previewUrl": string // 簡報（pptx/ppt）回傳可預覽的 pdf 衍生檔 URL（前端用 PDF 預覽器顯示）；其餘為 None。

用與 `file` 欄位相同的 CustomizedFileFieldSerializer 產 URL，確保格式一致（含各
storage provider 的 presign/host 規則）。不可用 get_absolute_url()——它產出的 URL 格式錯誤。
      "createdAt": string (timestamp)
    }
  ]
  "citationNodes": [
    {
      "chatbotTextNode": {
      {
        "id": string (uuid)
        "charactersCount": integer
        "hitsCount": integer
        "text": string
        "updatedAt": string (timestamp)
        "filename": string
        "chatbotFile": object // 返回 ChatbotFile 的完整資訊，包含檔案 URL 和類型，以支援前端圖片預覽
        "knowledgeBaseFile": object // 與 get_chatbot_file 相同，提供向後兼容
        "pageNumber": integer // Backward-compatible alias of ``page_start``.
        "pageStart": integer
        "pageEnd": integer
        "citationTitle": string // Source title shown on the inline citation hover card.
        "citationDescription": string // Source description shown on the inline citation hover card.
        "citationQuote": string // Quoted text snippet shown on the inline citation hover card.
        "hasImage": boolean // 判斷是否包含圖片（檢查檔案類型或 text 中的 Markdown 圖片）
        "imageUrl": string // 提取圖片 URL（優先使用檔案 URL，否則從 Markdown 提取）
        "displayText": string // 返回移除圖片 Markdown 標記的完整文字
        "displayTitle": string // 返回顯示標題（fallback: citation_title -> filename）
        "highlightedText": string // Return text with matched terms wrapped in ``<mark>`` tags.

Priority:
1. ES/OpenSearch native highlight (set by retrieve_api via ``_es_highlighted_text``)
2. Python regex fallback (keyword-based, works for all backends)
        "labels": [
          {
            "id": string (uuid)
            "name": string
          }
        ]
        "rawUserDefineMetadata"?: object // Metadata keys and values defined by the user. (非必填)
        "metadataEnabledForSearch": object // Map each user-defined metadata key on this node to whether it was sent into the LLM.

A key reaches the LLM only when its ``MetadataKey.enabled_for_search`` is True *and*
the node carries a value for it. Since this maps over ``raw_user_define_metadata``
(the keys the cited-documents block displays, all of which have a value),
``enabled_for_search`` alone decides the flag. The source of truth is the node's
knowledge base ``MetadataKey`` current setting, matching the AI Search indicator.
        "startCharIdx": integer
        "endCharIdx": integer
      }
      }
      "score"?: number (double) // 非必填
      "displayScore": integer
      "citationNumber"?: integer // Citation number matching the [1], [2] markers in the reply content (非必填)
      "highlightedText"?: string // ES/OpenSearch highlight result with <mark> tags (非必填)
    }
  ]
  "canvas"?: { // 非必填
  {
    "id": string (uuid)
    "name": string
    "canvasType": 
    {
    }
    "title": string
    "content": string
    "createdAt": string (timestamp)
  }
  }
  "slideTemplate"?:  // 非必填
  {
    "slug": string
    "displayName": string
    "thumbnailUrls"?: [ // 非必填
      string
    ]
  }
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
  "recordId": string // 返回 Message 對應的 ChatbotRecord ID

Note:
    對於未儲存的 Message（如 streaming 中的虛擬 Message），直接返回 None，
    避免觸發 OneToOneField reverse relation 的 DB 查詢（N+1 問題）。
  "broadcast"?: boolean // 非必填
  "skipCopilotTrigger"?: boolean // 非必填
  "activeRevisionNumber": integer
  "revisions": [
    {
      "id": string (uuid)
      "revisionNumber": integer
      "content": string
      "contentPayload": object
      "isActive": boolean
      "createdAt": string (timestamp)
    }
  ]
  "suggestedForId"?: string (uuid) // 非必填
  "suggestionStatus": string
  "suggestionTriggerSource": string
  "suggestionError": string
  "retryCount": integer // How many times the LLM call was auto-retried during this message generation. Currently only Bedrock first-chunk stall triggers retry (max 1). Detailed per-attempt records live in metadata["retry_attempts"].
  "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
    string (uuid)
  ]
  "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
    string (uuid)
  ]
  "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
  "videoGeneration": object // Return the latest GeneratedVideo state for FE reload recovery;
``errorMessage`` is blank to match the socket emit (raw value stays on the DB row).
  "isGreeting": boolean // Whether this message is a greeting message.
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation": "550e8400-e29b-41d4-a716-446655440000",
  "sender": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串"
  },
  "type": "回應字串",
  "content": "回應字串",
  "contentPayload": null,
  "feedback": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": {},
    "suggestion": "回應字串",
    "updatedAt": "回應字串"
  },
  "createdAt": "回應字串",
  "attachments": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "type": {},
      "filename": "回應字串",
      "file": "https://example.com/file.jpg",
      "expiresAt": "回應字串",
      "conversation": "550e8400-e29b-41d4-a716-446655440000"
    }
  ],
  "citations": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "filename": "回應字串",
      "file": "https://example.com/file.jpg",
      "fileType": "回應字串",
      "knowledgeBase": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      },
      "size": 456,
      "status": {},
      "parser": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "provider": {},
        "isTimestampSttProvider": false
      },
      "labels": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應字串"
        }
      ],
      "rawUserDefineMetadata": null,
      "speakerLabels": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "originalLabel": "回應字串",
          "customName": "回應字串",
          "displayName": "回應字串"
        }
      ],
      "vectorStorageSize": 456,
      "chunksCount": 456,
      "waitingTime": 456,
      "processingTime": 456,
      "processingTimeDetails": null,
      "ocrStatus": "回應字串",
      "ocrSkippedReason": "回應字串",
      "previewUrl": "回應字串",
      "createdAt": "回應字串"
    }
  ],
  "citationNodes": [
    {
      "chatbotTextNode": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "charactersCount": 456,
        "hitsCount": 456,
        "text": "回應字串",
        "updatedAt": "回應字串",
        "filename": "回應字串",
        "chatbotFile": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應範例名稱",
          "description": "回應範例描述"
        },
        "knowledgeBaseFile": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應範例名稱",
          "description": "回應範例描述"
        },
        "pageNumber": 456,
        "pageStart": 456,
        "pageEnd": 456,
        "citationTitle": "回應字串",
        "citationDescription": "回應字串",
        "citationQuote": "回應字串",
        "hasImage": false,
        "imageUrl": "回應字串",
        "displayText": "回應字串",
        "displayTitle": "回應字串",
        "highlightedText": "回應字串",
        "labels": [
          {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應字串"
          }
        ],
        "rawUserDefineMetadata": null,
        "metadataEnabledForSearch": {
          "key1": "value1",
          "key2": "value2",
          "createdAt": "2025-01-01T00:00:00.000Z"
        },
        "startCharIdx": 456,
        "endCharIdx": 456
      },
      "score": 456,
      "displayScore": 456,
      "citationNumber": 456,
      "highlightedText": "回應字串"
    }
  ],
  "canvas": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "canvasType": {},
    "title": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "slideTemplate": {
    "slug": "回應字串",
    "displayName": "回應字串",
    "thumbnailUrls": [
      "回應字串"
    ]
  },
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "recordId": "回應字串",
  "broadcast": false,
  "skipCopilotTrigger": false,
  "activeRevisionNumber": 456,
  "revisions": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "revisionNumber": 456,
      "content": "回應字串",
      "contentPayload": null,
      "isActive": false,
      "createdAt": "回應字串"
    }
  ],
  "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
  "suggestionStatus": "回應字串",
  "suggestionTriggerSource": "回應字串",
  "suggestionError": "回應字串",
  "retryCount": 456,
  "skillIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "toolIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "templateId": "550e8400-e29b-41d4-a716-446655440000",
  "videoGeneration": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "isGreeting": false
}
```

***

### 建立新的對話 <a href="#conversations-create" id="conversations-create"></a>

POST `/api/v1/conversations/`

#### 請求內容

**請求參數**

| 欄位               | 類型            | 必填 | 說明 |
| ---------------- | ------------- | -- | -- |
| webChat          | string (uuid) | 是  |    |
| contact          | string (uuid) | 否  |    |
| clientPlatform   | object        | 否  |    |
| workingDirectory | string        | 否  |    |

**請求結構範例**

```typescript
{
  "webChat": string (uuid)
  "contact"?: string (uuid) // 非必填
  "clientPlatform"?:  // 非必填
  {
  }
  "workingDirectory"?: string // 非必填
}
```

**請求範例值**

```json
{
  "webChat": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/conversations/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webChat": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "webChat": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  };

axios.post("https://api.maiagent.ai/api/v1/conversations/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "webChat": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/conversations/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'webChat' => '3fa85f64-5717-4562-b3fc-2c963f66afa6'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 取得訊息列表 <a href="#messages-list" id="messages-list"></a>

GET `/api/v1/messages/`

#### 參數

| 參數名稱           | 必填 | 類型      | 說明                                    |
| -------------- | -- | ------- | ------------------------------------- |
| `conversation` | ✅  | string  | 對話 ID                                 |
| `cursor`       | ❌  | string  | The pagination cursor value.          |
| `pageSize`     | ❌  | integer | Number of results to return per page. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/messages/?conversation=example&cursor=example&pageSize=1" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/messages/?conversation=example&cursor=example&pageSize=1", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/?conversation=example&cursor=example&pageSize=1"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/messages/?conversation=example&cursor=example&pageSize=1", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "count": integer
  "next"?: string (uri) // 非必填
  "previous"?: string (uri) // 非必填
  "results": [
    {
      "id": string (uuid)
      "conversation": string (uuid)
      "sender": 
      {
        "id": string (uuid)
        "name": string
        "avatar": string
        "email"?: string (email) // 非必填
        "phoneNumber"?: string // 非必填
      }
      "type"?: string // 非必填
      "content"?: string // 非必填
      "contentPayload"?: object // 非必填
      "feedback": 
      {
        "id": string (uuid)
        "type": 
        {
        }
        "suggestion"?: string // 非必填
        "updatedAt": string (timestamp)
      }
      "createdAt": string (timestamp)
      "attachments"?: [ // 非必填
        {
          "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
          "type"?:  // 非必填
          {
          }
          "filename": string
          "file": string (uri)
          "expiresAt": string // ISO datetime when this attachment will be auto-deleted.

For conversation-bound attachments: conversation.last_message_created_at + retention_days.
For attachments without a conversation: created_at + retention_days.
Returns None when cleanup is disabled (effective_from not set).
          "conversation"?: string (uuid) // 非必填
        }
      ]
      "citations": [
        {
          "id": string (uuid)
          "filename": string // 檔案名稱
          "file": string (uri) // 要上傳的檔案
          "fileType": string
          "knowledgeBase"?:  // 非必填
          {
            "id": string (uuid)
            "name": string
          }
          "size": integer // File size in bytes
          "status": 
          {
          }
          "parser": 
          {
            "id": string (uuid)
            "name": string
            "provider": 
            {
            }
            "isTimestampSttProvider": boolean
          }
          "labels"?: [ // 非必填
            {
              "id": string (uuid)
              "name": string
            }
          ]
          "rawUserDefineMetadata"?: object // 非必填
          "speakerLabels": [
            {
              "id": string (uuid)
              "originalLabel": string // Original speaker label from diarization (e.g., SPEAKER_00)
              "customName"?: string // User-defined speaker name (e.g., John) (非必填)
              "displayName": string
            }
          ]
          "vectorStorageSize": integer // Size of vectors for this file in Elasticsearch (bytes)
          "chunksCount": integer // Number of chunks/nodes generated from this file
          "waitingTime": number (double)
          "processingTime": number (double)
          "processingTimeDetails": object
          "ocrStatus": string // 掃描頁 OCR 結果：done、skipped、partial、off；解析前或舊檔案為 null
          "ocrSkippedReason": string // 掃描頁沒做 OCR 的原因：no_azure_settings、azure_unavailable、insufficient_credits、transient_error、time_budget、disabled；有做完時為 null
          "previewUrl": string // 簡報（pptx/ppt）回傳可預覽的 pdf 衍生檔 URL（前端用 PDF 預覽器顯示）；其餘為 None。

用與 `file` 欄位相同的 CustomizedFileFieldSerializer 產 URL，確保格式一致（含各
storage provider 的 presign/host 規則）。不可用 get_absolute_url()——它產出的 URL 格式錯誤。
          "createdAt": string (timestamp)
        }
      ]
      "citationNodes": [
        {
          "chatbotTextNode": {
          {
            "id": string (uuid)
            "charactersCount": integer
            "hitsCount": integer
            "text": string
            "updatedAt": string (timestamp)
            "filename": string
            "chatbotFile": object // 返回 ChatbotFile 的完整資訊，包含檔案 URL 和類型，以支援前端圖片預覽
            "knowledgeBaseFile": object // 與 get_chatbot_file 相同，提供向後兼容
            "pageNumber": integer // Backward-compatible alias of ``page_start``.
            "pageStart": integer
            "pageEnd": integer
            "citationTitle": string // Source title shown on the inline citation hover card.
            "citationDescription": string // Source description shown on the inline citation hover card.
            "citationQuote": string // Quoted text snippet shown on the inline citation hover card.
            "hasImage": boolean // 判斷是否包含圖片（檢查檔案類型或 text 中的 Markdown 圖片）
            "imageUrl": string // 提取圖片 URL（優先使用檔案 URL，否則從 Markdown 提取）
            "displayText": string // 返回移除圖片 Markdown 標記的完整文字
            "displayTitle": string // 返回顯示標題（fallback: citation_title -> filename）
            "highlightedText": string // Return text with matched terms wrapped in ``<mark>`` tags.

Priority:
1. ES/OpenSearch native highlight (set by retrieve_api via ``_es_highlighted_text``)
2. Python regex fallback (keyword-based, works for all backends)
            "labels": [
              {
                "id": string (uuid)
                "name": string
              }
            ]
            "rawUserDefineMetadata"?: object // Metadata keys and values defined by the user. (非必填)
            "metadataEnabledForSearch": object // Map each user-defined metadata key on this node to whether it was sent into the LLM.

A key reaches the LLM only when its ``MetadataKey.enabled_for_search`` is True *and*
the node carries a value for it. Since this maps over ``raw_user_define_metadata``
(the keys the cited-documents block displays, all of which have a value),
``enabled_for_search`` alone decides the flag. The source of truth is the node's
knowledge base ``MetadataKey`` current setting, matching the AI Search indicator.
            "startCharIdx": integer
            "endCharIdx": integer
          }
          }
          "score"?: number (double) // 非必填
          "displayScore": integer
          "citationNumber"?: integer // Citation number matching the [1], [2] markers in the reply content (非必填)
          "highlightedText"?: string // ES/OpenSearch highlight result with <mark> tags (非必填)
        }
      ]
      "canvas"?: { // 非必填
      {
        "id": string (uuid)
        "name": string
        "canvasType": 
        {
        }
        "title": string
        "content": string
        "createdAt": string (timestamp)
      }
      }
      "slideTemplate"?:  // 非必填
      {
        "slug": string
        "displayName": string
        "thumbnailUrls"?: [ // 非必填
          string
        ]
      }
      "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
      {
        "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
          {
            "knowledgeBaseId": string (uuid) // 知識庫 ID
            "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
              string (uuid)
            ]
            "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
              string (uuid)
            ]
            "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
              string (uuid)
            ]
            "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
          }
        ]
        "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
        {
          "operator": string (enum: AND, OR) // 標籤條件的組合方式
          "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
            object
          ]
        }
        }
      }
      }
      "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
      "recordId": string // 返回 Message 對應的 ChatbotRecord ID

Note:
    對於未儲存的 Message（如 streaming 中的虛擬 Message），直接返回 None，
    避免觸發 OneToOneField reverse relation 的 DB 查詢（N+1 問題）。
      "broadcast"?: boolean // 非必填
      "skipCopilotTrigger"?: boolean // 非必填
      "activeRevisionNumber": integer
      "revisions": [
        {
          "id": string (uuid)
          "revisionNumber": integer
          "content": string
          "contentPayload": object
          "isActive": boolean
          "createdAt": string (timestamp)
        }
      ]
      "suggestedForId"?: string (uuid) // 非必填
      "suggestionStatus": string
      "suggestionTriggerSource": string
      "suggestionError": string
      "retryCount": integer // How many times the LLM call was auto-retried during this message generation. Currently only Bedrock first-chunk stall triggers retry (max 1). Detailed per-attempt records live in metadata["retry_attempts"].
      "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
        string (uuid)
      ]
      "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
        string (uuid)
      ]
      "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
      "videoGeneration": object // Return the latest GeneratedVideo state for FE reload recovery;
``errorMessage`` is blank to match the socket emit (raw value stays on the DB row).
      "isGreeting": boolean // Whether this message is a greeting message.
    }
  ]
}
```

**回應範例值**

```json
{
  "count": 123,
  "next": "http://api.example.org/accounts/?page=4",
  "previous": "http://api.example.org/accounts/?page=2",
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "conversation": "550e8400-e29b-41d4-a716-446655440000",
      "sender": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "avatar": "回應字串",
        "email": "response@example.com",
        "phoneNumber": "回應字串"
      },
      "type": "回應字串",
      "content": "回應字串",
      "contentPayload": null,
      "feedback": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": {},
        "suggestion": "回應字串",
        "updatedAt": "回應字串"
      },
      "createdAt": "回應字串",
      "attachments": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "type": {},
          "filename": "回應字串",
          "file": "https://example.com/file.jpg",
          "expiresAt": "回應字串",
          "conversation": "550e8400-e29b-41d4-a716-446655440000"
        }
      ],
      "citations": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "filename": "回應字串",
          "file": "https://example.com/file.jpg",
          "fileType": "回應字串",
          "knowledgeBase": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應字串"
          },
          "size": 456,
          "status": {},
          "parser": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應字串",
            "provider": {},
            "isTimestampSttProvider": false
          },
          "labels": [
            {
              "id": "550e8400-e29b-41d4-a716-446655440000",
              "name": "回應字串"
            }
          ],
          "rawUserDefineMetadata": null,
          "speakerLabels": [
            {
              "id": "550e8400-e29b-41d4-a716-446655440000",
              "originalLabel": "回應字串",
              "customName": "回應字串",
              "displayName": "回應字串"
            }
          ],
          "vectorStorageSize": 456,
          "chunksCount": 456,
          "waitingTime": 456,
          "processingTime": 456,
          "processingTimeDetails": null,
          "ocrStatus": "回應字串",
          "ocrSkippedReason": "回應字串",
          "previewUrl": "回應字串",
          "createdAt": "回應字串"
        }
      ],
      "citationNodes": [
        {
          "chatbotTextNode": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "charactersCount": 456,
            "hitsCount": 456,
            "text": "回應字串",
            "updatedAt": "回應字串",
            "filename": "回應字串",
            "chatbotFile": {
              "id": "550e8400-e29b-41d4-a716-446655440000",
              "name": "回應範例名稱",
              "description": "回應範例描述"
            },
            "knowledgeBaseFile": {
              "id": "550e8400-e29b-41d4-a716-446655440000",
              "name": "回應範例名稱",
              "description": "回應範例描述"
            },
            "pageNumber": 456,
            "pageStart": 456,
            "pageEnd": 456,
            "citationTitle": "回應字串",
            "citationDescription": "回應字串",
            "citationQuote": "回應字串",
            "hasImage": false,
            "imageUrl": "回應字串",
            "displayText": "回應字串",
            "displayTitle": "回應字串",
            "highlightedText": "回應字串",
            "labels": [
              {
                "id": "550e8400-e29b-41d4-a716-446655440000",
                "name": "回應字串"
              }
            ],
            "rawUserDefineMetadata": null,
            "metadataEnabledForSearch": {
              "key1": "value1",
              "key2": "value2",
              "createdAt": "2025-01-01T00:00:00.000Z"
            },
            "startCharIdx": 456,
            "endCharIdx": 456
          },
          "score": 456,
          "displayScore": 456,
          "citationNumber": 456,
          "highlightedText": "回應字串"
        }
      ],
      "canvas": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "canvasType": {},
        "title": "回應字串",
        "content": "回應字串",
        "createdAt": "回應字串"
      },
      "slideTemplate": {
        "slug": "回應字串",
        "displayName": "回應字串",
        "thumbnailUrls": [
          "回應字串"
        ]
      },
      "queryMetadata": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "metadata": null,
      "recordId": "回應字串",
      "broadcast": false,
      "skipCopilotTrigger": false,
      "activeRevisionNumber": 456,
      "revisions": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "revisionNumber": 456,
          "content": "回應字串",
          "contentPayload": null,
          "isActive": false,
          "createdAt": "回應字串"
        }
      ],
      "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
      "suggestionStatus": "回應字串",
      "suggestionTriggerSource": "回應字串",
      "suggestionError": "回應字串",
      "retryCount": 456,
      "skillIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ],
      "toolIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ],
      "templateId": "550e8400-e29b-41d4-a716-446655440000",
      "videoGeneration": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "isGreeting": false
    }
  ]
}
```

***

### 取得特定訊息 <a href="#messages-retrieve" id="messages-retrieve"></a>

GET `/api/v1/messages/{id}/`

#### 參數

| 參數名稱           | 必填 | 類型     | 說明                                      |
| -------------- | -- | ------ | --------------------------------------- |
| `id`           | ✅  | string | A UUID string identifying this Message. |
| `conversation` | ✅  | string | 對話 ID                                   |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/messages/550e8400-e29b-41d4-a716-446655440000/?conversation=example" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/messages/550e8400-e29b-41d4-a716-446655440000/?conversation=example", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/550e8400-e29b-41d4-a716-446655440000/?conversation=example"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/messages/550e8400-e29b-41d4-a716-446655440000/?conversation=example", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "conversation": string (uuid)
  "sender": 
  {
    "id": string (uuid)
    "name": string
    "avatar": string
    "email"?: string (email) // 非必填
    "phoneNumber"?: string // 非必填
  }
  "type"?: string // 非必填
  "content"?: string // 非必填
  "contentPayload"?: object // 非必填
  "feedback": 
  {
    "id": string (uuid)
    "type": 
    {
    }
    "suggestion"?: string // 非必填
    "updatedAt": string (timestamp)
  }
  "createdAt": string (timestamp)
  "attachments"?: [ // 非必填
    {
      "id": string (uuid) // ID of an already-uploaded attachment, as returned by the attachment upload endpoint. Required: a missing, null or non-UUID id is rejected with HTTP 400 and the message is not created.
      "type"?:  // 非必填
      {
      }
      "filename": string
      "file": string (uri)
      "expiresAt": string // ISO datetime when this attachment will be auto-deleted.

For conversation-bound attachments: conversation.last_message_created_at + retention_days.
For attachments without a conversation: created_at + retention_days.
Returns None when cleanup is disabled (effective_from not set).
      "conversation"?: string (uuid) // 非必填
    }
  ]
  "citations": [
    {
      "id": string (uuid)
      "filename": string // 檔案名稱
      "file": string (uri) // 要上傳的檔案
      "fileType": string
      "knowledgeBase"?:  // 非必填
      {
        "id": string (uuid)
        "name": string
      }
      "size": integer // File size in bytes
      "status": 
      {
      }
      "parser": 
      {
        "id": string (uuid)
        "name": string
        "provider": 
        {
        }
        "isTimestampSttProvider": boolean
      }
      "labels"?: [ // 非必填
        {
          "id": string (uuid)
          "name": string
        }
      ]
      "rawUserDefineMetadata"?: object // 非必填
      "speakerLabels": [
        {
          "id": string (uuid)
          "originalLabel": string // Original speaker label from diarization (e.g., SPEAKER_00)
          "customName"?: string // User-defined speaker name (e.g., John) (非必填)
          "displayName": string
        }
      ]
      "vectorStorageSize": integer // Size of vectors for this file in Elasticsearch (bytes)
      "chunksCount": integer // Number of chunks/nodes generated from this file
      "waitingTime": number (double)
      "processingTime": number (double)
      "processingTimeDetails": object
      "ocrStatus": string // 掃描頁 OCR 結果：done、skipped、partial、off；解析前或舊檔案為 null
      "ocrSkippedReason": string // 掃描頁沒做 OCR 的原因：no_azure_settings、azure_unavailable、insufficient_credits、transient_error、time_budget、disabled；有做完時為 null
      "previewUrl": string // 簡報（pptx/ppt）回傳可預覽的 pdf 衍生檔 URL（前端用 PDF 預覽器顯示）；其餘為 None。

用與 `file` 欄位相同的 CustomizedFileFieldSerializer 產 URL，確保格式一致（含各
storage provider 的 presign/host 規則）。不可用 get_absolute_url()——它產出的 URL 格式錯誤。
      "createdAt": string (timestamp)
    }
  ]
  "citationNodes": [
    {
      "chatbotTextNode": {
      {
        "id": string (uuid)
        "charactersCount": integer
        "hitsCount": integer
        "text": string
        "updatedAt": string (timestamp)
        "filename": string
        "chatbotFile": object // 返回 ChatbotFile 的完整資訊，包含檔案 URL 和類型，以支援前端圖片預覽
        "knowledgeBaseFile": object // 與 get_chatbot_file 相同，提供向後兼容
        "pageNumber": integer // Backward-compatible alias of ``page_start``.
        "pageStart": integer
        "pageEnd": integer
        "citationTitle": string // Source title shown on the inline citation hover card.
        "citationDescription": string // Source description shown on the inline citation hover card.
        "citationQuote": string // Quoted text snippet shown on the inline citation hover card.
        "hasImage": boolean // 判斷是否包含圖片（檢查檔案類型或 text 中的 Markdown 圖片）
        "imageUrl": string // 提取圖片 URL（優先使用檔案 URL，否則從 Markdown 提取）
        "displayText": string // 返回移除圖片 Markdown 標記的完整文字
        "displayTitle": string // 返回顯示標題（fallback: citation_title -> filename）
        "highlightedText": string // Return text with matched terms wrapped in ``<mark>`` tags.

Priority:
1. ES/OpenSearch native highlight (set by retrieve_api via ``_es_highlighted_text``)
2. Python regex fallback (keyword-based, works for all backends)
        "labels": [
          {
            "id": string (uuid)
            "name": string
          }
        ]
        "rawUserDefineMetadata"?: object // Metadata keys and values defined by the user. (非必填)
        "metadataEnabledForSearch": object // Map each user-defined metadata key on this node to whether it was sent into the LLM.

A key reaches the LLM only when its ``MetadataKey.enabled_for_search`` is True *and*
the node carries a value for it. Since this maps over ``raw_user_define_metadata``
(the keys the cited-documents block displays, all of which have a value),
``enabled_for_search`` alone decides the flag. The source of truth is the node's
knowledge base ``MetadataKey`` current setting, matching the AI Search indicator.
        "startCharIdx": integer
        "endCharIdx": integer
      }
      }
      "score"?: number (double) // 非必填
      "displayScore": integer
      "citationNumber"?: integer // Citation number matching the [1], [2] markers in the reply content (非必填)
      "highlightedText"?: string // ES/OpenSearch highlight result with <mark> tags (非必填)
    }
  ]
  "canvas"?: { // 非必填
  {
    "id": string (uuid)
    "name": string
    "canvasType": 
    {
    }
    "title": string
    "content": string
    "createdAt": string (timestamp)
  }
  }
  "slideTemplate"?:  // 非必填
  {
    "slug": string
    "displayName": string
    "thumbnailUrls"?: [ // 非必填
      string
    ]
  }
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "metadata"?: object // Message metadata, such as timezone and other environment information (非必填)
  "recordId": string // 返回 Message 對應的 ChatbotRecord ID

Note:
    對於未儲存的 Message（如 streaming 中的虛擬 Message），直接返回 None，
    避免觸發 OneToOneField reverse relation 的 DB 查詢（N+1 問題）。
  "broadcast"?: boolean // 非必填
  "skipCopilotTrigger"?: boolean // 非必填
  "activeRevisionNumber": integer
  "revisions": [
    {
      "id": string (uuid)
      "revisionNumber": integer
      "content": string
      "contentPayload": object
      "isActive": boolean
      "createdAt": string (timestamp)
    }
  ]
  "suggestedForId"?: string (uuid) // 非必填
  "suggestionStatus": string
  "suggestionTriggerSource": string
  "suggestionError": string
  "retryCount": integer // How many times the LLM call was auto-retried during this message generation. Currently only Bedrock first-chunk stall triggers retry (max 1). Detailed per-attempt records live in metadata["retry_attempts"].
  "skillIds"?: [ // Per-message selected skill IDs from the WebChat client (camelCase: skillIds). (非必填)
    string (uuid)
  ]
  "toolIds"?: [ // Per-message selected tool IDs from the WebChat client (camelCase: toolIds). (非必填)
    string (uuid)
  ]
  "templateId"?: string (uuid) // Document/sheet template ID for file-level compilation (camelCase: templateId). (非必填)
  "videoGeneration": object // Return the latest GeneratedVideo state for FE reload recovery;
``errorMessage`` is blank to match the socket emit (raw value stays on the DB row).
  "isGreeting": boolean // Whether this message is a greeting message.
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation": "550e8400-e29b-41d4-a716-446655440000",
  "sender": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串"
  },
  "type": "回應字串",
  "content": "回應字串",
  "contentPayload": null,
  "feedback": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": {},
    "suggestion": "回應字串",
    "updatedAt": "回應字串"
  },
  "createdAt": "回應字串",
  "attachments": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "type": {},
      "filename": "回應字串",
      "file": "https://example.com/file.jpg",
      "expiresAt": "回應字串",
      "conversation": "550e8400-e29b-41d4-a716-446655440000"
    }
  ],
  "citations": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "filename": "回應字串",
      "file": "https://example.com/file.jpg",
      "fileType": "回應字串",
      "knowledgeBase": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      },
      "size": 456,
      "status": {},
      "parser": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "provider": {},
        "isTimestampSttProvider": false
      },
      "labels": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應字串"
        }
      ],
      "rawUserDefineMetadata": null,
      "speakerLabels": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "originalLabel": "回應字串",
          "customName": "回應字串",
          "displayName": "回應字串"
        }
      ],
      "vectorStorageSize": 456,
      "chunksCount": 456,
      "waitingTime": 456,
      "processingTime": 456,
      "processingTimeDetails": null,
      "ocrStatus": "回應字串",
      "ocrSkippedReason": "回應字串",
      "previewUrl": "回應字串",
      "createdAt": "回應字串"
    }
  ],
  "citationNodes": [
    {
      "chatbotTextNode": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "charactersCount": 456,
        "hitsCount": 456,
        "text": "回應字串",
        "updatedAt": "回應字串",
        "filename": "回應字串",
        "chatbotFile": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應範例名稱",
          "description": "回應範例描述"
        },
        "knowledgeBaseFile": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應範例名稱",
          "description": "回應範例描述"
        },
        "pageNumber": 456,
        "pageStart": 456,
        "pageEnd": 456,
        "citationTitle": "回應字串",
        "citationDescription": "回應字串",
        "citationQuote": "回應字串",
        "hasImage": false,
        "imageUrl": "回應字串",
        "displayText": "回應字串",
        "displayTitle": "回應字串",
        "highlightedText": "回應字串",
        "labels": [
          {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應字串"
          }
        ],
        "rawUserDefineMetadata": null,
        "metadataEnabledForSearch": {
          "key1": "value1",
          "key2": "value2",
          "createdAt": "2025-01-01T00:00:00.000Z"
        },
        "startCharIdx": 456,
        "endCharIdx": 456
      },
      "score": 456,
      "displayScore": 456,
      "citationNumber": 456,
      "highlightedText": "回應字串"
    }
  ],
  "canvas": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "canvasType": {},
    "title": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "slideTemplate": {
    "slug": "回應字串",
    "displayName": "回應字串",
    "thumbnailUrls": [
      "回應字串"
    ]
  },
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "recordId": "回應字串",
  "broadcast": false,
  "skipCopilotTrigger": false,
  "activeRevisionNumber": 456,
  "revisions": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "revisionNumber": 456,
      "content": "回應字串",
      "contentPayload": null,
      "isActive": false,
      "createdAt": "回應字串"
    }
  ],
  "suggestedForId": "550e8400-e29b-41d4-a716-446655440000",
  "suggestionStatus": "回應字串",
  "suggestionTriggerSource": "回應字串",
  "suggestionError": "回應字串",
  "retryCount": 456,
  "skillIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "toolIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "templateId": "550e8400-e29b-41d4-a716-446655440000",
  "videoGeneration": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "isGreeting": false
}
```

***

### 取得對話列表 <a href="#conversations-list" id="conversations-list"></a>

GET `/api/v1/conversations/`

#### 參數

| 參數名稱                     | 必填 | 類型      | 說明                                                            |
| ------------------------ | -- | ------- | ------------------------------------------------------------- |
| `assignee`               | ❌  | string  |                                                               |
| `chatbot`                | ❌  | string  |                                                               |
| `contact`                | ❌  | string  | 聯絡人 ID                                                        |
| `contactTags`            | ❌  | array   | Multiple values may be separated by commas.                   |
| `cursor`                 | ❌  | string  | The pagination cursor value.                                  |
| `endDate`                | ❌  | string  |                                                               |
| `externalConversationId` | ❌  | string  |                                                               |
| `externalSource`         | ❌  | string  |                                                               |
| `inbox`                  | ❌  | string  | 對話平台 ID                                                       |
| `isPinned`               | ❌  | string  |                                                               |
| `keyword`                | ❌  | string  | 關鍵字搜尋                                                         |
| `kind`                   | ❌  | string  | \`chat\`: Chat ; \`secretary\`: Secretary;                    |
| `mine`                   | ❌  | boolean |                                                               |
| `mode`                   | ❌  | string  | \`chat\`: Chat ; \`cowork\`: Cowork;                          |
| `pageSize`               | ❌  | integer | Number of results to return per page.                         |
| `startDate`              | ❌  | string  |                                                               |
| `status`                 | ❌  | array   | \`open\`: Open ; \`resolved\`: Resolved ; \`queued\`: Queued; |
| `tags`                   | ❌  | array   | Multiple values may be separated by commas.                   |
| `unassigned`             | ❌  | boolean |                                                               |
| `updatedAfter`           | ❌  | string  |                                                               |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/conversations/?assignee=550e8400-e29b-41d4-a716-446655440000&chatbot=550e8400-e29b-41d4-a716-446655440000&contact=550e8400-e29b-41d4-a716-446655440000&contactTags=example&cursor=example&endDate=example&externalConversationId=example&externalSource=example&inbox=550e8400-e29b-41d4-a716-446655440000&isPinned=example&keyword=example&kind=chat&mine=true&mode=chat&pageSize=1&startDate=example&status=example&tags=example&unassigned=true&updatedAfter=2025-01-01T00:00:00.000Z" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/conversations/?assignee=550e8400-e29b-41d4-a716-446655440000&chatbot=550e8400-e29b-41d4-a716-446655440000&contact=550e8400-e29b-41d4-a716-446655440000&contactTags=example&cursor=example&endDate=example&externalConversationId=example&externalSource=example&inbox=550e8400-e29b-41d4-a716-446655440000&isPinned=example&keyword=example&kind=chat&mine=true&mode=chat&pageSize=1&startDate=example&status=example&tags=example&unassigned=true&updatedAfter=2025-01-01T00:00:00.000Z", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/?assignee=550e8400-e29b-41d4-a716-446655440000&chatbot=550e8400-e29b-41d4-a716-446655440000&contact=550e8400-e29b-41d4-a716-446655440000&contactTags=example&cursor=example&endDate=example&externalConversationId=example&externalSource=example&inbox=550e8400-e29b-41d4-a716-446655440000&isPinned=example&keyword=example&kind=chat&mine=true&mode=chat&pageSize=1&startDate=example&status=example&tags=example&unassigned=true&updatedAfter=2025-01-01T00:00:00.000Z"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/conversations/?assignee=550e8400-e29b-41d4-a716-446655440000&chatbot=550e8400-e29b-41d4-a716-446655440000&contact=550e8400-e29b-41d4-a716-446655440000&contactTags=example&cursor=example&endDate=example&externalConversationId=example&externalSource=example&inbox=550e8400-e29b-41d4-a716-446655440000&isPinned=example&keyword=example&kind=chat&mine=true&mode=chat&pageSize=1&startDate=example&status=example&tags=example&unassigned=true&updatedAfter=2025-01-01T00:00:00.000Z", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "count": integer
  "next"?: string (uri) // 非必填
  "previous"?: string (uri) // 非必填
  "results": [
    {
      "id": string (uuid)
      "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
      {
        "id": string (uuid)
        "name": string
        "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
        "email"?: // 可能有不同的類型 (非必填)
        string (email) // 非必填
        "phoneNumber"?: string // 非必填
        "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
        "sourceId"?: string // 非必填
        "tags": [
          {
            "id": string (uuid)
            "name": string
          }
        ]
      }
      }
      "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
      {
        "id": string (uuid)
        "name": string
        "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
        "unreadConversationsCount"?: integer // 非必填
        "signAuth"?:  // 非必填
        {
          "id": string (uuid)
          "signSource": string (uuid)
          "signParams": {
          {
            "keycloak": 
            {
              "clientId": string
              "url": string
              "realm": string
            }
            "line": 
            {
              "liffId": string
            }
            "ad": 
            {
              "saml": string
            }
            "google"?:  // 非必填
            {
              "enabled": boolean
            }
          }
          }
          "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
          "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
          {
          }
          "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
          {
          }
          "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
          "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
            string
          ]
          "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
        }
        "enableAnalysis"?: boolean // 非必填
      }
      }
      "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
      "title": string
      "lastMessage"?: { // 非必填
      {
        "id": string (uuid)
        "type"?: string // 非必填
        "content"?: string // 非必填
        "createdAt": string (timestamp)
      }
      }
      "callRecord": 
      {
        "id": string (uuid)
        "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
        "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
        "isActive": boolean
        "canHangup": boolean
      }
      "lastMessageCreatedAt": string (timestamp)
      "unreadMessagesCount": integer
      "autoReplyEnabled": boolean
      "isAutoReplyNow": boolean
      "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
      "lastReadAt": string (timestamp)
      "createdAt": string (timestamp)
      "isGroupChat": boolean
      "enableGroupMention"?: boolean // 非必填
      "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
      {
        "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
          {
            "knowledgeBaseId": string (uuid) // 知識庫 ID
            "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
              string (uuid)
            ]
            "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
              string (uuid)
            ]
            "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
              string (uuid)
            ]
            "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
          }
        ]
        "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
        {
          "operator": string (enum: AND, OR) // 標籤條件的組合方式
          "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
            object
          ]
        }
        }
      }
      }
      "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
      "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
      "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
      "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
      {
        "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
        "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
        "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
        "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
        "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
      }
      }
      "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
      "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
      "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
      {
      }
      "deepResearchOutputFormat": // 可能有不同的類型
      string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
      "ipAddress": string
      "ipCountryCode": string
      "ipRecordedAt": string (timestamp)
      "assignee": 
      {
        "id": string (uuid)
        "name": string
        "userId": string (uuid)
      }
      "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
      "tags": [
        {
          "id": string (uuid)
          "name": string
          "memberIds"?: [ // 非必填
            string (uuid)
          ]
        }
      ]
      "progressStatus": string
      "firstResponseAt"?: string (timestamp) // 非必填
      "queuedAt"?: string (timestamp) // 非必填
      "assignedAt"?: string (timestamp) // 非必填
      "transferReason"?: string // 非必填
      "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
      "satisfactionComment": string
      "satisfactionSubmittedAt": string (timestamp)
      "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
      "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
      {
      }
      "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
      "slideProjectId": string
      "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
      "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
      "matchedMessageId": string
      "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
      "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
      "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
      "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
      "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
      "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
      "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
      "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
      "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
      "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
      "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
    }
  ]
}
```

**回應範例值**

```json
{
  "count": 123,
  "next": "http://api.example.org/accounts/?page=4",
  "previous": "http://api.example.org/accounts/?page=2",
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "contact": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "avatar": "回應字串",
        "email": "response@example.com",
        "phoneNumber": "回應字串",
        "metadata": null,
        "sourceId": "回應字串",
        "tags": [
          {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應字串"
          }
        ]
      },
      "inbox": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "channelType": "line",
        "unreadConversationsCount": 456,
        "signAuth": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "signSource": "550e8400-e29b-41d4-a716-446655440000",
          "signParams": {
            "keycloak": {
              "clientId": "回應字串",
              "url": "回應字串",
              "realm": "回應字串"
            },
            "line": {
              "liffId": "回應字串"
            },
            "ad": {
              "saml": "回應字串"
            },
            "google": {
              "enabled": false
            }
          },
          "sourceIdAccessEnabled": false,
          "sourceIdVerifyMode": {},
          "sourceIdSignatureTtlMinutes": {},
          "keycloakTokenPassthrough": false,
          "keycloakTokenPassthroughAllowedHosts": [
            "回應字串"
          ],
          "organizationLogin": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "回應範例名稱",
            "description": "回應範例描述"
          }
        },
        "enableAnalysis": false
      },
      "chatbot": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "title": "回應字串",
      "lastMessage": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": "回應字串",
        "content": "回應字串",
        "createdAt": "回應字串"
      },
      "callRecord": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "status": "initiated",
        "direction": "inbound",
        "isActive": false,
        "canHangup": false
      },
      "lastMessageCreatedAt": "回應字串",
      "unreadMessagesCount": 456,
      "autoReplyEnabled": false,
      "isAutoReplyNow": false,
      "willAiReplyNow": false,
      "lastReadAt": "回應字串",
      "createdAt": "回應字串",
      "isGroupChat": false,
      "enableGroupMention": false,
      "queryMetadata": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "toolMask": null,
      "connectorMask": null,
      "thinkingConfig": null,
      "thinkingConfigSchema": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "effectiveThinkingConfig": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "llm": "550e8400-e29b-41d4-a716-446655440000",
      "deepResearchStatus": {},
      "deepResearchOutputFormat": "canvas",
      "ipAddress": "回應字串",
      "ipCountryCode": "回應字串",
      "ipRecordedAt": "回應字串",
      "assignee": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串",
        "userId": "550e8400-e29b-41d4-a716-446655440000"
      },
      "status": "open",
      "tags": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "name": "回應字串",
          "memberIds": [
            "550e8400-e29b-41d4-a716-446655440000"
          ]
        }
      ],
      "progressStatus": "回應字串",
      "firstResponseAt": "回應字串",
      "queuedAt": "回應字串",
      "assignedAt": "回應字串",
      "transferReason": "回應字串",
      "satisfactionScore": 456,
      "satisfactionComment": "回應字串",
      "satisfactionSubmittedAt": "回應字串",
      "latestAnalysisSummary": "回應字串",
      "clientPlatform": {},
      "workingDirectory": "回應字串",
      "slideProjectId": "回應字串",
      "matchedField": "回應字串",
      "matchedSnippet": "回應字串",
      "matchedMessageId": "回應字串",
      "pinnedAt": "回應字串",
      "folder": "550e8400-e29b-41d4-a716-446655440000",
      "hasActiveBrowserSession": false,
      "callerOrganizationId": "回應字串",
      "handoff": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "displayContextUsage": false,
      "autoSplitReason": "回應字串",
      "continuedFrom": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "continuedTo": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "continuationSummary": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "conversationKind": "回應字串"
    }
  ]
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 取得特定對話 <a href="#conversations-retrieve" id="conversations-retrieve"></a>

GET `/api/v1/conversations/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 重新命名對話 <a href="#conversations-rename-partial-update" id="conversations-rename-partial-update"></a>

PATCH `/api/v1/conversations/{id}/rename/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位    | 類型     | 必填 | 說明 |
| ----- | ------ | -- | -- |
| title | string | 否  |    |

**請求結構範例**

```typescript
{
  "title"?: string // 非必填
}
```

**請求範例值**

```json
{
  "title": "範例名稱"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/rename/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "範例名稱"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "title": "範例名稱"
  };

axios.patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/rename/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/rename/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "title": "範例名稱"
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/rename/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'title' => '範例名稱'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 刪除對話 <a href="#conversations-destroy" id="conversations-destroy"></a>

DELETE `/api/v1/conversations/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

// 請求內容 (payload)
const data = null;

axios.delete("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.delete(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->delete("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明                                                                 |
| --- | ------------------------------------------------------------------ |
| 204 | No response body                                                   |
| 4XX | Error response; X-Error-Code carries its code (see "Error codes"). |

***

### 中止 AI 回覆 <a href="#conversations-stop-response-create" id="conversations-stop-response-create"></a>

POST `/api/v1/conversations/{conversationId}/stop-response/`

#### 參數

| 參數名稱             | 必填 | 類型     | 說明 |
| ---------------- | -- | ------ | -- |
| `conversationId` | ✅  | string |    |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/stop-response/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

// 請求內容 (payload)
const data = null;

axios.post("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/stop-response/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/stop-response/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.post(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/stop-response/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明                                                                 |
| --- | ------------------------------------------------------------------ |
| 200 | No response body                                                   |
| 4XX | Error response; X-Error-Code carries its code (see "Error codes"). |

***

### 提交對話滿意度 <a href="#conversations-satisfaction-create" id="conversations-satisfaction-create"></a>

POST `/api/v1/conversations/{id}/satisfaction/`

{% hint style="info" %}
每個對話只能提交一次。
{% endhint %}

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位                  | 類型      | 必填 | 說明                                                                                          |
| ------------------- | ------- | -- | ------------------------------------------------------------------------------------------- |
| satisfactionScore   | integer | 是  | Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied) |
| satisfactionComment | string  | 否  |                                                                                             |

**請求結構範例**

```typescript
{
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment"?: string // 非必填
}
```

**請求範例值**

```json
{
  "satisfactionScore": 5,
  "satisfactionComment": "回答清楚，問題已解決"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/satisfaction/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "satisfactionScore": 5,
    "satisfactionComment": "回答清楚，問題已解決"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "satisfactionScore": 5,
    "satisfactionComment": "回答清楚，問題已解決"
  };

axios.post("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/satisfaction/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/satisfaction/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "satisfactionScore": 5,
    "satisfactionComment": "回答清楚，問題已解決"
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/satisfaction/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'satisfactionScore' => 5,
            'satisfactionComment' => '回答清楚，問題已解決'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "satisfactionScore": integer
  "satisfactionComment"?: string // 非必填
  "satisfactionSubmittedAt": string // 提交時間，ISO 8601 UTC 字串，例如 2026-10-09T15:10:48.717193Z
}
```

**回應範例值**

```json
{
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串"
}
```

**狀態碼: 409 - 此對話已提交過滿意度**

***

### 列出對話事件 <a href="#conversations-events-retrieve" id="conversations-events-retrieve"></a>

GET `/api/v1/conversations/{id}/events/`

{% hint style="info" %}
轉真人流程的事件紀錄（`event_type`：`transfer_triggered`／`human_assigned`／`returned_to_ai`／`queue_timeout`），可與 Webhook 對帳。流程見技術手冊[客服系統串接](https://docs.maiagent.ai/tech/api-integration/customer-service-system-integration)。
{% endhint %}

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/events/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/events/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/events/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/events/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 指派對話給成員 <a href="#conversations-assign-partial-update" id="conversations-assign-partial-update"></a>

PATCH `/api/v1/conversations/{id}/assign/`

{% hint style="info" %}
設定接手成員並停用 AI 自動回覆；排隊中的對話會轉為進行中。
{% endhint %}

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位             | 類型             | 必填 | 說明 |
| -------------- | -------------- | -- | -- |
| assignee       | string (uuid)  | 否  |    |
| transferReason | string         | 否  |    |
| tagIds         | array\[string] | 否  |    |

**請求結構範例**

```typescript
{
  "assignee"?: string (uuid) // 非必填
  "transferReason"?: string // 非必填
  "tagIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "assignee": "550e8400-e29b-41d4-a716-446655440000",
  "transferReason": "範例字串",
  "tagIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/assign/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/assign/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/assign/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/assign/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'assignee' => '550e8400-e29b-41d4-a716-446655440000',
            'transferReason' => '範例字串',
            'tagIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 認領對話 <a href="#conversations-claim-partial-update" id="conversations-claim-partial-update"></a>

PATCH `/api/v1/conversations/{id}/claim/`

{% hint style="info" %}
以呼叫者本人為接手成員，效果同「指派對話」。
{% endhint %}

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位             | 類型             | 必填 | 說明 |
| -------------- | -------------- | -- | -- |
| transferReason | string         | 否  |    |
| tagIds         | array\[string] | 否  |    |

**請求結構範例**

```typescript
{
  "transferReason"?: string // 非必填
  "tagIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "transferReason": "範例字串",
  "tagIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/claim/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/claim/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/claim/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "transferReason": "範例字串",
    "tagIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/claim/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'transferReason' => '範例字串',
            'tagIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 轉接對話給其他成員 <a href="#conversations-transfer-partial-update" id="conversations-transfer-partial-update"></a>

PATCH `/api/v1/conversations/{id}/transfer/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位             | 類型             | 必填 | 說明 |
| -------------- | -------------- | -- | -- |
| assignee       | string (uuid)  | 否  |    |
| transferReason | string         | 否  |    |
| tagIds         | array\[string] | 否  |    |

**請求結構範例**

```typescript
{
  "assignee"?: string (uuid) // 非必填
  "transferReason"?: string // 非必填
  "tagIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "assignee": "550e8400-e29b-41d4-a716-446655440000",
  "transferReason": "範例字串",
  "tagIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/transfer/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/transfer/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/transfer/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "assignee": "550e8400-e29b-41d4-a716-446655440000",
    "transferReason": "範例字串",
    "tagIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/transfer/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'assignee' => '550e8400-e29b-41d4-a716-446655440000',
            'transferReason' => '範例字串',
            'tagIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 轉回 AI 回覆 <a href="#conversations-return-to-ai-partial-update" id="conversations-return-to-ai-partial-update"></a>

PATCH `/api/v1/conversations/{id}/return-to-ai/`

{% hint style="info" %}
清除接手成員並恢復 AI 自動回覆；完成後會送出 `handoff.returned_to_ai` Webhook 事件。
{% endhint %}

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                           |
| ---- | -- | ------ | -------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Conversation. |

#### 請求內容

**請求參數**

| 欄位                  | 類型      | 必填 | 說明 |
| ------------------- | ------- | -- | -- |
| requireContextReady | boolean | 否  |    |

**請求結構範例**

```typescript
{
  "requireContextReady"?: boolean // 非必填
}
```

**請求範例值**

```json
{
  "requireContextReady": true
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/return-to-ai/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "requireContextReady": true
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "requireContextReady": true
  };

axios.patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/return-to-ai/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/return-to-ai/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "requireContextReady": True
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/conversations/550e8400-e29b-41d4-a716-446655440000/return-to-ai/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'requireContextReady' => true
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "contact": { // 輕量級 Contact Serializer，用於 Conversation List view

只包含 List view 必要的欄位，移除 inboxes、mcp_credentials 和 api_credentials
以避免 N+1 查詢問題。email / phone_number / metadata 為 Contact 自身的純量欄位，
前端對話側欄需要顯示，無 N+1 成本。
  {
    "id": string (uuid)
    "name": string
    "avatar"?: string // Stores our own media as a relative storage key, or an external CDN URL as-is. (非必填)
    "email"?: // 可能有不同的類型 (非必填)
    string (email) // 非必填
    "phoneNumber"?: string // 非必填
    "metadata"?: object // Custom customer information shown in the customer panel of the conversation page (非必填)
    "sourceId"?: string // 非必填
    "tags": [
      {
        "id": string (uuid)
        "name": string
      }
    ]
  }
  }
  "inbox": { // Inbox summary embedded in a conversation payload.

``unread_conversations_count`` stays here because it is part of the
documented REST conversation API. It is an org-wide denormalized
counter, so WS emit paths must run the payload through
:func:`strip_org_wide_unread_count` before broadcasting it to rooms
that include members without ``GroupInbox.can_view_conversations``.
  {
    "id": string (uuid)
    "name": string
    "channelType": string (enum: line, telegram, teams, web, messenger, instagram, email, whatsapp, slack, team_plus, line_works, viber) // * `line` - LINE
* `telegram` - Telegram
* `teams` - Teams
* `web` - Web
* `messenger` - Messenger
* `instagram` - Instagram
* `email` - Email
* `whatsapp` - WhatsApp
* `slack` - Slack
* `team_plus` - Team+
* `line_works` - LINE WORKS
* `viber` - Viber
    "unreadConversationsCount"?: integer // 非必填
    "signAuth"?:  // 非必填
    {
      "id": string (uuid)
      "signSource": string (uuid)
      "signParams": {
      {
        "keycloak": 
        {
          "clientId": string
          "url": string
          "realm": string
        }
        "line": 
        {
          "liffId": string
        }
        "ad": 
        {
          "saml": string
        }
        "google"?:  // 非必填
        {
          "enabled": boolean
        }
      }
      }
      "sourceIdAccessEnabled"?: boolean // When enabled, embedded visitors presenting a Source ID (verified per the verify mode below) may chat without going through the login flow. Disabled keeps every existing behavior unchanged. (非必填)
      "sourceIdVerifyMode"?:  // "Require signature verification": the embedding site must send an HMAC signature computed on its backend. "Source ID only": anyone knowing a Source ID can act as that contact; suitable only for testing or closed networks.

* `signature` - Require signature verification
* `raw` - Source ID only (非必填)
      {
      }
      "sourceIdSignatureTtlMinutes"?:  // How long a signature can be used to obtain the contact identity. Not a session lifetime: once exchanged, the session follows the existing WebChat mechanism.

* `1` - 1
* `5` - 5
* `15` - 15 (非必填)
      {
      }
      "keycloakTokenPassthrough"?: boolean // When enabled, the Keycloak access token a visitor logged in with is forwarded as the Authorization header when the AI calls MCP and API tools on their behalf, so tools do not require a separate per-tool login. Only for the Keycloak sign source. Never overrides an Authorization header a tool already resolves from its own credentials. The visitor identity is the organization member bound to the conversation at login, never the contact Source ID. (非必填)
      "keycloakTokenPassthroughAllowedHosts"?: [ // Hostnames (or "*.example.com" wildcards) of the tools the visitor Keycloak token may be sent to (非必填)
        string
      ]
      "organizationLogin": object // How visitors sign in when the sign source is "organization" (mirrors the back-office login); null for other sign sources
    }
    "enableAnalysis"?: boolean // 非必填
  }
  }
  "chatbot": object // Chatbot (Agent) summary from the conversation's inbox, already eager-loaded.

``is_maigpt`` lets the client tell the default MaiGPT agent apart (icon, feature
gate) without comparing against the organization's ``maigpt_inbox`` id;
``file_workspace_mode`` is the effective P6 mode (MaiGPT, blueprint and the
organization's file-library switch already applied).
  "title": string
  "lastMessage"?: { // 非必填
  {
    "id": string (uuid)
    "type"?: string // 非必填
    "content"?: string // 非必填
    "createdAt": string (timestamp)
  }
  }
  "callRecord": 
  {
    "id": string (uuid)
    "status"?: string (enum: initiated, ringing, in-progress, completed, failed, busy, no-answer, canceled) // * `initiated` - Initiated
* `ringing` - Ringing
* `in-progress` - In Progress
* `completed` - Completed
* `failed` - Failed
* `busy` - Busy
* `no-answer` - No Answer
* `canceled` - Canceled (非必填)
    "direction": string (enum: inbound, outbound) // * `inbound` - Inbound
* `outbound` - Outbound
    "isActive": boolean
    "canHangup": boolean
  }
  "lastMessageCreatedAt": string (timestamp)
  "unreadMessagesCount": integer
  "autoReplyEnabled": boolean
  "isAutoReplyNow": boolean
  "willAiReplyNow": boolean // Whether a text message arriving through the inbox gets an AI reply right now.

The messaging channels are gated by ``is_auto_reply_now`` (auto reply on and inside the
inbox auto-reply schedule) and by the inbox having a chatbot. The chatbot's API web chat
is answered by the completions endpoint, which ignores the schedule, so there the
conversation switch alone decides. The channel is only looked up for a web inbox outside
its schedule.

Surfaces that ignore the schedule on any inbox answer from their own rule instead: the
completions endpoint continuing an existing conversation (``completions_progress_status``)
and voice turns, which the voice agent answers.
  "lastReadAt": string (timestamp)
  "createdAt": string (timestamp)
  "isGroupChat": boolean
  "enableGroupMention"?: boolean // 非必填
  "queryMetadata"?: { // 查詢元資料，控制可查詢的知識範圍；詳見各端點說明 (非必填)
  {
    "knowledgeBases"?: [ // 可查詢的知識庫清單；空陣列或 null＝全部不可查（無權限），未提供＝不限制 (非必填)
      {
        "knowledgeBaseId": string (uuid) // 知識庫 ID
        "chatbotFileIds"?: [ // 檔案 ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "knowledgeBaseFileIds"?: [ // 檔案 ID 清單（chatbotFileIds 的新名稱；兩者皆提供時以本欄位為準） (非必填)
          string (uuid)
        ]
        "faqIds"?: [ // FAQ ID 清單（依 hasUserSelectedAll 決定為排除或僅選取） (非必填)
          string (uuid)
        ]
        "hasUserSelectedAll"?: boolean // true＝選取知識庫全部內容並排除清單中的項目；false＝僅選取清單中的項目 (非必填)
      }
    ]
    "labelRelations"?: { // 標籤過濾條件；conditions 為空陣列＝不做標籤過濾（並非無權限）。必須與 knowledgeBases 一併提供——單獨提供時知識庫檢索不會套用標籤過濾（等同不限制） (非必填)
    {
      "operator": string (enum: AND, OR) // 標籤條件的組合方式
      "conditions"?: [ // 標籤條件清單，支援巢狀 operator/conditions 組合 (非必填)
        object
      ]
    }
    }
  }
  }
  "toolMask"?: object // Enabled/disabled state per tool: {tool_id: bool} (非必填)
  "connectorMask"?: object // Enabled/disabled state per connector: {connector_id: bool} (非必填)
  "thinkingConfig"?: object // None = not set (inherit the chatbot setting); otherwise {"reasoning_effort": <level>} (非必填)
  "thinkingConfigSchema": { // 此模型的思考設定表單；null 表示此模型沒有思考設定
  {
    "type"?: string // 表單類型，固定為 reasoning_effort (非必填)
    "fields"?: object // reasoning_effort 欄位：options 列出此模型接受的思考等級（由弱到強），default 固定為 null (非必填)
    "canDisable"?: boolean // 此模型能否關閉思考；true 時 options 含 off (非必填)
    "unsetBehavior"?: string (enum: off, model_default) // 對話與助理都沒設思考等級時的實際行為：off＝不思考（最快）；model_default＝模型自行思考，或平台預設等級會開啟思考 (非必填)
    "unsetLevel"?: string // 沒設等級時平台實際送出的等級；null 表示不送思考參數，交給模型自身預設 (非必填)
  }
  }
  "effectiveThinkingConfig": object // The level the next reply sends on this conversation's model, after gating and clamping.

The stored choice resolves conversation > chatbot > the LLM row's default level; None means
the model sends no thinking parameter, so the provider default applies.
  "llm": string (uuid) // The model the next reply runs on: the conversation's pin, else its assistant's current model.

TC-0205: returning the stored ``conversation.llm`` would show a model an unpinned conversation no
longer uses once its assistant switches model, while ``thinking_config_schema`` already follows the
effective model. Read-only: displaying it never marks the conversation as explicitly selected;
only the update-llm endpoint does.
  "deepResearchStatus":  // Status of deep research for this conversation

* `not_used` - Not Used
* `started` - Started
* `running` - Running
* `completed` - Completed
* `failed` - Failed
  {
  }
  "deepResearchOutputFormat": // 可能有不同的類型
  string (enum: canvas, chat, file) // Chosen delivery form for the finished report. Set only when the user clicks a format in the pre-research choice card; reset to NULL each time Deep Research is (re-)armed. NULL means no explicit choice (or a plan-skipping request) and falls back to Canvas at render time, but stays distinct from an explicit canvas pick so the frontend can lock the card only after a real selection. To roll back to fixed-Canvas behavior, force this to NULL/canvas — no redeploy needed.

* `canvas` - Canvas
* `chat` - Chat reply
* `file` - Downloadable file
  "ipAddress": string
  "ipCountryCode": string
  "ipRecordedAt": string (timestamp)
  "assignee": 
  {
    "id": string (uuid)
    "name": string
    "userId": string (uuid)
  }
  "status"?: string (enum: open, resolved, queued) // * `open` - Open
* `resolved` - Resolved
* `queued` - Queued (非必填)
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "memberIds"?: [ // 非必填
        string (uuid)
      ]
    }
  ]
  "progressStatus": string
  "firstResponseAt"?: string (timestamp) // 非必填
  "queuedAt"?: string (timestamp) // 非必填
  "assignedAt"?: string (timestamp) // 非必填
  "transferReason"?: string // 非必填
  "satisfactionScore": integer // Conversation satisfaction rating on a 5-point scale (1=very dissatisfied, 5=very satisfied)
  "satisfactionComment": string
  "satisfactionSubmittedAt": string (timestamp)
  "latestAnalysisSummary": string // The conversation's current analysis summary (its active summary revision).

Reads the `latest_analysis_summary` annotation added by `setup_eager_loading`
to avoid an N+1 query. All read paths (list / retrieve / create) eager-load,
so the annotation is present; it falls back to '' only for instances built
outside `setup_eager_loading`.
  "clientPlatform":  // Client platform that created this conversation (web, desktop)

* `web` - Web
* `desktop` - Desktop
  {
  }
  "workingDirectory": string // Absolute path of the local folder bound to a desktop conversation. Only set for desktop conversations; null for web conversations.
  "slideProjectId": string
  "matchedField": string // Cached per instance: ``get_matched_message_id`` / ``get_matched_snippet``
both read this, so resolving it once avoids recomputing the keyword and
title-match logic three times per serialized conversation.
  "matchedSnippet": string // Keyword-centred excerpt of the matched message, with ellipses.

Reads the ``matched_message_content`` annotation added by
``ConversationViewSet._annotate_keyword_match``; no extra query.
  "matchedMessageId": string
  "pinnedAt": string (timestamp) // When the conversation was pinned. Null means unpinned.
  "folder": string (uuid) // The user-defined sidebar folder this conversation is grouped into. Null means unclassified (shown under the time groups). Deleting the folder resets this to null without deleting the conversation.
  "hasActiveBrowserSession": boolean // Whether a browser_use session snapshot exists to resume.

Lets the frontend know it should proactively re-request the browser
panel (emit ``browser:start``) after a page reload, instead of only
ever showing the panel when a live ``browser:frame`` push happens to
arrive first.
  "callerOrganizationId": string // Bound caller organization (stamped at conversation start); null when unbound
  "handoff": object // 交接資訊：enabled=平台開關；接續對話帶 source_conversation_id/source_title；被交接的原對話帶 continued_to_conversation_id/continued_to_title 與 latest_summary_message_id
  "displayContextUsage": boolean // 是否顯示上下文使用量百分比條（對話平台開關，MaiGPT 恆為 true；與交接開關互相獨立）
  "autoSplitReason": string // 對話自動切分產生本對話的原因：resolved（解決後）／idle（閒置）；非切分產生為 null
  "continuedFrom": object // 切分產生的對話接續自哪一通：{id, last_message_at, deleted}；舊對話已刪除時 id=null、deleted=true
  "continuedTo": object // 最新一通由本對話切分出去的對話：{id, created_at}；沒有為 null
  "continuationSummary": object // 接續摘要：{state: disabled|pending|ready|not_applied, items: [{conversation_id, content, generated_at, last_message_at, old_status}]}（items 新到舊）；非切分產生為 null
  "conversationKind": string // chat = a chat with an agent; secretary = the member's personal secretary Work chat
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "contact": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "avatar": "回應字串",
    "email": "response@example.com",
    "phoneNumber": "回應字串",
    "metadata": null,
    "sourceId": "回應字串",
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      }
    ]
  },
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "channelType": "line",
    "unreadConversationsCount": 456,
    "signAuth": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "signSource": "550e8400-e29b-41d4-a716-446655440000",
      "signParams": {
        "keycloak": {
          "clientId": "回應字串",
          "url": "回應字串",
          "realm": "回應字串"
        },
        "line": {
          "liffId": "回應字串"
        },
        "ad": {
          "saml": "回應字串"
        },
        "google": {
          "enabled": false
        }
      },
      "sourceIdAccessEnabled": false,
      "sourceIdVerifyMode": {},
      "sourceIdSignatureTtlMinutes": {},
      "keycloakTokenPassthrough": false,
      "keycloakTokenPassthroughAllowedHosts": [
        "回應字串"
      ],
      "organizationLogin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    },
    "enableAnalysis": false
  },
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "title": "回應字串",
  "lastMessage": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "回應字串",
    "content": "回應字串",
    "createdAt": "回應字串"
  },
  "callRecord": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "initiated",
    "direction": "inbound",
    "isActive": false,
    "canHangup": false
  },
  "lastMessageCreatedAt": "回應字串",
  "unreadMessagesCount": 456,
  "autoReplyEnabled": false,
  "isAutoReplyNow": false,
  "willAiReplyNow": false,
  "lastReadAt": "回應字串",
  "createdAt": "回應字串",
  "isGroupChat": false,
  "enableGroupMention": false,
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "toolMask": null,
  "connectorMask": null,
  "thinkingConfig": null,
  "thinkingConfigSchema": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "effectiveThinkingConfig": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llm": "550e8400-e29b-41d4-a716-446655440000",
  "deepResearchStatus": {},
  "deepResearchOutputFormat": "canvas",
  "ipAddress": "回應字串",
  "ipCountryCode": "回應字串",
  "ipRecordedAt": "回應字串",
  "assignee": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串",
    "userId": "550e8400-e29b-41d4-a716-446655440000"
  },
  "status": "open",
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
      ]
    }
  ],
  "progressStatus": "回應字串",
  "firstResponseAt": "回應字串",
  "queuedAt": "回應字串",
  "assignedAt": "回應字串",
  "transferReason": "回應字串",
  "satisfactionScore": 456,
  "satisfactionComment": "回應字串",
  "satisfactionSubmittedAt": "回應字串",
  "latestAnalysisSummary": "回應字串",
  "clientPlatform": {},
  "workingDirectory": "回應字串",
  "slideProjectId": "回應字串",
  "matchedField": "回應字串",
  "matchedSnippet": "回應字串",
  "matchedMessageId": "回應字串",
  "pinnedAt": "回應字串",
  "folder": "550e8400-e29b-41d4-a716-446655440000",
  "hasActiveBrowserSession": false,
  "callerOrganizationId": "回應字串",
  "handoff": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "displayContextUsage": false,
  "autoSplitReason": "回應字串",
  "continuedFrom": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuedTo": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "continuationSummary": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "conversationKind": "回應字串"
}
```

**狀態碼: 409 - Agent context not ready: \`detail\` plus \`agentContext\` (pending / failed writes)**

***

### 列出對話產出檔案 <a href="#conversations-outputs-retrieve" id="conversations-outputs-retrieve"></a>

GET `/api/v1/conversations/{conversationId}/outputs/`

{% hint style="info" %}
回應欄位（`count`、`source`、`results[]`）、可見範圍與排序見技術手冊[對話產出清單 API](https://docs.maiagent.ai/tech/api-integration/endpoint-behaviors/conversation-outputs-api)。
{% endhint %}

#### 參數

| 參數名稱             | 必填 | 類型     | 說明 |
| ---------------- | -- | ------ | -- |
| `conversationId` | ✅  | string |    |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/conversations/{conversationId}/outputs/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/conversations/{conversationId}/outputs/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/{conversationId}/outputs/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/conversations/{conversationId}/outputs/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明                                                                 |
| --- | ------------------------------------------------------------------ |
| 200 | No response body                                                   |
| 4XX | Error response; X-Error-Code carries its code (see "Error codes"). |

***

### 分享對話 <a href="#conversations-share-create" id="conversations-share-create"></a>

POST `/api/v1/conversations/{conversationPk}/share/`

#### 參數

| 參數名稱             | 必填 | 類型     | 說明 |
| ---------------- | -- | ------ | -- |
| `conversationPk` | ✅  | string |    |

#### 請求內容

**請求參數**

| 欄位          | 類型                                         | 必填 | 說明                                                                |
| ----------- | ------------------------------------------ | -- | ----------------------------------------------------------------- |
| shareScope  | string (enum: organization, group, member) | 是  | `organization`: Organization ; `group`: Group ; `member`: Member; |
| permission  | object                                     | 否  |                                                                   |
| title       | string                                     | 否  |                                                                   |
| description | string                                     | 否  |                                                                   |
| groupIds    | array\[string]                             | 否  |                                                                   |
| memberIds   | array\[string]                             | 否  |                                                                   |

**請求結構範例**

```typescript
{
  "shareScope": string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member
  "permission"?:  // 非必填
  {
  }
  "title"?: string // 非必填
  "description"?: string // 非必填
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "shareScope": "organization",
  "permission": {},
  "title": "範例名稱",
  "description": "範例字串",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.post("https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'shareScope' => 'organization',
            'permission' => new \stdClass(),
            'title' => '範例名稱',
            'description' => '範例字串',
            'groupIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'memberIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "shareScope": string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member
  "permission"?:  // 非必填
  {
  }
  "title"?: string // 非必填
  "description"?: string // 非必填
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**回應範例值**

```json
{
  "shareScope": "organization",
  "permission": {},
  "title": "回應字串",
  "description": "回應字串",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 快速分享對話 <a href="#conversations-share-quick-create" id="conversations-share-quick-create"></a>

POST `/api/v1/conversations/{conversationPk}/share/quick/`

#### 參數

| 參數名稱             | 必填 | 類型     | 說明 |
| ---------------- | -- | ------ | -- |
| `conversationPk` | ✅  | string |    |

#### 請求內容

**請求參數**

| 欄位          | 類型                                         | 必填 | 說明                                                                |
| ----------- | ------------------------------------------ | -- | ----------------------------------------------------------------- |
| shareScope  | string (enum: organization, group, member) | 是  | `organization`: Organization ; `group`: Group ; `member`: Member; |
| permission  | object                                     | 否  |                                                                   |
| title       | string                                     | 否  |                                                                   |
| description | string                                     | 否  |                                                                   |
| groupIds    | array\[string]                             | 否  |                                                                   |
| memberIds   | array\[string]                             | 否  |                                                                   |

**請求結構範例**

```typescript
{
  "shareScope": string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member
  "permission"?:  // 非必填
  {
  }
  "title"?: string // 非必填
  "description"?: string // 非必填
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "shareScope": "organization",
  "permission": {},
  "title": "範例名稱",
  "description": "範例字串",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/quick/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.post("https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/quick/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/quick/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "shareScope": "organization",
    "permission": {},
    "title": "範例名稱",
    "description": "範例字串",
    "groupIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/conversations/{conversationPk}/share/quick/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'shareScope' => 'organization',
            'permission' => new \stdClass(),
            'title' => '範例名稱',
            'description' => '範例字串',
            'groupIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'memberIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "shareScope": string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member
  "permission"?:  // 非必填
  {
  }
  "title"?: string // 非必填
  "description"?: string // 非必填
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**回應範例值**

```json
{
  "shareScope": "organization",
  "permission": {},
  "title": "回應字串",
  "description": "回應字串",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

**狀態碼: 4XX - Error response; X-Error-Code carries its code (see "Error codes").**

***

### 列出分享的對話 <a href="#shared-conversations-list" id="shared-conversations-list"></a>

GET `/api/v1/shared-conversations/`

#### 參數

| 參數名稱       | 必填 | 類型      | 說明                                             |
| ---------- | -- | ------- | ---------------------------------------------- |
| `page`     | ❌  | integer | A page number within the paginated result set. |
| `pageSize` | ❌  | integer | Number of results to return per page.          |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/shared-conversations/?page=1&pageSize=1" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/shared-conversations/?page=1&pageSize=1", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/?page=1&pageSize=1"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/shared-conversations/?page=1&pageSize=1", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "count": integer
  "next"?: string (uri) // 非必填
  "previous"?: string (uri) // 非必填
  "results": [
    {
      "id": string (uuid)
      "title": string // Custom title for the shared conversation
      "description": string // Custom description for the shared conversation
      "shareScope": 
      {
      }
      "permission": 
      {
      }
      "sharedBy": 
      {
        "id": string (uuid)
        "name": string
      }
      "isOwner": boolean
      "messageCount": integer // Messages the share shows; the view counts a whole page at once (``context['message_counts']``).
      "createdAt": string (timestamp)
    }
  ]
}
```

**回應範例值**

```json
{
  "count": 123,
  "next": "http://api.example.org/accounts/?page=4",
  "previous": "http://api.example.org/accounts/?page=2",
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "title": "回應字串",
      "description": "回應字串",
      "shareScope": {},
      "permission": {},
      "sharedBy": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      },
      "isOwner": false,
      "messageCount": 456,
      "createdAt": "回應字串"
    }
  ]
}
```

***

### 取得特定分享對話 <a href="#shared-conversations-retrieve" id="shared-conversations-retrieve"></a>

GET `/api/v1/shared-conversations/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                                  |
| ---- | -- | ------ | --------------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Shared Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "title": string // Custom title for the shared conversation
  "description": string // Custom description for the shared conversation
  "shareScope": 
  {
  }
  "permission": 
  {
  }
  "sharedBy": 
  {
    "id": string (uuid)
    "name": string
  }
  "isOwner": boolean
  "conversationId": string (uuid) // The original conversation, exposed only to the sharer while the share still follows it ("continue").
  "groupIds": [ // Current recipients, for the sharer's settings dialog only.
    string (uuid)
  ]
  "memberIds": [ // Recipients that are still active members, so saving the dialog back as-is stays valid.
    string (uuid)
  ]
  "needsContinueReminder": boolean // True when the sharer can continue the original conversation and has not been warned yet.
  "createdAt": string (timestamp)
  "conversationSnapshot": object
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "回應字串",
  "description": "回應字串",
  "shareScope": {},
  "permission": {},
  "sharedBy": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "isOwner": false,
  "conversationId": "550e8400-e29b-41d4-a716-446655440000",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "needsContinueReminder": false,
  "createdAt": "回應字串",
  "conversationSnapshot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  }
}
```

***

### 更新分享對話 <a href="#shared-conversations-partial-update" id="shared-conversations-partial-update"></a>

PATCH `/api/v1/shared-conversations/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                                  |
| ---- | -- | ------ | --------------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Shared Conversation. |

#### 請求內容

**請求參數**

| 欄位          | 類型                                         | 必填 | 說明                                                                |
| ----------- | ------------------------------------------ | -- | ----------------------------------------------------------------- |
| title       | string                                     | 否  |                                                                   |
| description | string                                     | 否  |                                                                   |
| permission  | string (enum: readonly, copy)              | 否  | `readonly`: Read Only ; `copy`: Copyable;                         |
| shareScope  | string (enum: organization, group, member) | 否  | `organization`: Organization ; `group`: Group ; `member`: Member; |
| groupIds    | array\[string]                             | 否  |                                                                   |
| memberIds   | array\[string]                             | 否  |                                                                   |

**請求結構範例**

```typescript
{
  "title"?: string // 非必填
  "description"?: string // 非必填
  "permission"?: string (enum: readonly, copy) // * `readonly` - Read Only
* `copy` - Copyable (非必填)
  "shareScope"?: string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member (非必填)
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**請求範例值**

```json
{
  "title": "範例名稱",
  "description": "範例字串",
  "permission": "readonly",
  "shareScope": "organization",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "範例名稱",
    "description": "範例字串",
    "permission": "readonly",
    "shareScope": "organization",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "title": "範例名稱",
    "description": "範例字串",
    "permission": "readonly",
    "shareScope": "organization",
    "groupIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  };

axios.patch("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "title": "範例名稱",
    "description": "範例字串",
    "permission": "readonly",
    "shareScope": "organization",
    "groupIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "memberIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ]
}

response = requests.patch(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->patch("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'title' => '範例名稱',
            'description' => '範例字串',
            'permission' => 'readonly',
            'shareScope' => 'organization',
            'groupIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'memberIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "title"?: string // 非必填
  "description"?: string // 非必填
  "permission"?: string (enum: readonly, copy) // * `readonly` - Read Only
* `copy` - Copyable (非必填)
  "shareScope"?: string (enum: organization, group, member) // * `organization` - Organization
* `group` - Group
* `member` - Member (非必填)
  "groupIds"?: [ // 非必填
    string (uuid)
  ]
  "memberIds"?: [ // 非必填
    string (uuid)
  ]
}
```

**回應範例值**

```json
{
  "title": "回應字串",
  "description": "回應字串",
  "permission": "readonly",
  "shareScope": "organization",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ]
}
```

***

### 刪除分享對話 <a href="#shared-conversations-destroy" id="shared-conversations-destroy"></a>

DELETE `/api/v1/shared-conversations/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                                  |
| ---- | -- | ------ | --------------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Shared Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

// 請求內容 (payload)
const data = null;

axios.delete("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.delete(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->delete("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明               |
| --- | ---------------- |
| 204 | No response body |

***

### 複製分享對話 <a href="#shared-conversations-fork-create" id="shared-conversations-fork-create"></a>

POST `/api/v1/shared-conversations/{id}/fork/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                                  |
| ---- | -- | ------ | --------------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Shared Conversation. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/fork/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {};

axios.post("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/fork/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/fork/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/shared-conversations/550e8400-e29b-41d4-a716-446655440000/fork/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => new \stdClass()
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "title": string // Custom title for the shared conversation
  "description": string // Custom description for the shared conversation
  "shareScope": 
  {
  }
  "permission": 
  {
  }
  "sharedBy": 
  {
    "id": string (uuid)
    "name": string
  }
  "isOwner": boolean
  "conversationId": string (uuid) // The original conversation, exposed only to the sharer while the share still follows it ("continue").
  "groupIds": [ // Current recipients, for the sharer's settings dialog only.
    string (uuid)
  ]
  "memberIds": [ // Recipients that are still active members, so saving the dialog back as-is stays valid.
    string (uuid)
  ]
  "needsContinueReminder": boolean // True when the sharer can continue the original conversation and has not been warned yet.
  "createdAt": string (timestamp)
  "conversationSnapshot": object
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "回應字串",
  "description": "回應字串",
  "shareScope": {},
  "permission": {},
  "sharedBy": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "isOwner": false,
  "conversationId": "550e8400-e29b-41d4-a716-446655440000",
  "groupIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "memberIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "needsContinueReminder": false,
  "createdAt": "回應字串",
  "conversationSnapshot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  }
}
```

***

### 取得我的分享列表 <a href="#shared-conversations-my-shares-retrieve" id="shared-conversations-my-shares-retrieve"></a>

GET `/api/v1/shared-conversations/my-shares/`

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/shared-conversations/my-shares/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/shared-conversations/my-shares/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/shared-conversations/my-shares/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/shared-conversations/my-shares/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "title": string // Custom title for the shared conversation
  "description": string // Custom description for the shared conversation
  "shareScope": 
  {
  }
  "permission": 
  {
  }
  "sharedBy": 
  {
    "id": string (uuid)
    "name": string
  }
  "isOwner": boolean
  "messageCount": integer // Messages the share shows; the view counts a whole page at once (``context['message_counts']``).
  "createdAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "回應字串",
  "description": "回應字串",
  "shareScope": {},
  "permission": {},
  "sharedBy": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "isOwner": false,
  "messageCount": 456,
  "createdAt": "回應字串"
}
```

***

### 建立訊息回饋 <a href="#messages-feedback-create" id="messages-feedback-create"></a>

POST `/api/v1/messages/{messagePk}/feedback/`

#### 參數

| 參數名稱        | 必填 | 類型     | 說明 |
| ----------- | -- | ------ | -- |
| `messagePk` | ✅  | string |    |

#### 請求內容

**請求參數**

| 欄位         | 類型     | 必填 | 說明 |
| ---------- | ------ | -- | -- |
| type       | object | 是  |    |
| suggestion | string | 否  |    |

**請求結構範例**

```typescript
{
  "type": 
  {
  }
  "suggestion"?: string // 非必填
}
```

**請求範例值**

```json
{
  "type": {},
  "suggestion": "範例字串"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": {},
    "suggestion": "範例字串"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "type": {},
    "suggestion": "範例字串"
  };

axios.post("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "type": {},
    "suggestion": "範例字串"
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'type' => new \stdClass(),
            'suggestion' => '範例字串'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "type": 
  {
  }
  "suggestion"?: string // 非必填
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": {},
  "suggestion": "回應字串",
  "updatedAt": "回應字串"
}
```

**狀態碼: 400 - 此訊息已有回饋，請使用 PATCH 方法更新**

***

### 更新訊息回饋 <a href="#messages-feedback-update" id="messages-feedback-update"></a>

PUT `/api/v1/messages/{messagePk}/feedback/{id}/`

#### 參數

| 參數名稱        | 必填 | 類型     | 說明                                               |
| ----------- | -- | ------ | ------------------------------------------------ |
| `id`        | ✅  | string | A UUID string identifying this Message Feedback. |
| `messagePk` | ✅  | string |                                                  |

#### 請求內容

**請求參數**

| 欄位         | 類型     | 必填 | 說明 |
| ---------- | ------ | -- | -- |
| type       | object | 是  |    |
| suggestion | string | 否  |    |

**請求結構範例**

```typescript
{
  "type": 
  {
  }
  "suggestion"?: string // 非必填
}
```

**請求範例值**

```json
{
  "type": {},
  "suggestion": "範例字串"
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X PUT "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": {},
    "suggestion": "範例字串"
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "type": {},
    "suggestion": "範例字串"
  };

axios.put("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "type": {},
    "suggestion": "範例字串"
}

response = requests.put(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->put("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'type' => new \stdClass(),
            'suggestion' => '範例字串'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "type": 
  {
  }
  "suggestion"?: string // 非必填
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": {},
  "suggestion": "回應字串",
  "updatedAt": "回應字串"
}
```

***

### 刪除訊息回饋 <a href="#messages-feedback-destroy" id="messages-feedback-destroy"></a>

DELETE `/api/v1/messages/{messagePk}/feedback/{id}/`

#### 參數

| 參數名稱        | 必填 | 類型     | 說明                                               |
| ----------- | -- | ------ | ------------------------------------------------ |
| `id`        | ✅  | string | A UUID string identifying this Message Feedback. |
| `messagePk` | ✅  | string |                                                  |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

// 請求內容 (payload)
const data = null;

axios.delete("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.delete(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->delete("https://api.maiagent.ai/api/v1/messages/{messagePk}/feedback/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

| 狀態碼 | 說明          |
| --- | ----------- |
| 204 | 成功刪除回饋      |
| 400 | 此回饋不屬於指定的訊息 |

***

### 取得對話紀錄列表 <a href="#records-list" id="records-list"></a>

GET `/api/v1/records/`

#### 參數

| 參數名稱                 | 必填 | 類型      | 說明                                                                                                                                                                                                                           |
| -------------------- | -- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `callerMember`       | ❌  | array   | Multiple values may be separated by commas.                                                                                                                                                                                  |
| `chatbot`            | ❌  | string  | 篩選特定 AI 助理 (UUID)                                                                                                                                                                                                            |
| `endDate`            | ❌  | string  | 結束日期（格式：YYYY-MM-DD，如：2025-01-31）                                                                                                                                                                                             |
| `endDatetime`        | ❌  | string  |                                                                                                                                                                                                                              |
| `errorType`          | ❌  | array   | Multiple values may be separated by commas. \`system\`: System ; \`llm\`: LLM ; \`embedding\`: Embedding ; \`reranker\`: Reranker ; \`vector\_db\`: Vector DB ; \`workflow\`: Workflow ; \`tool\`: Tool ; \`timeout\`: Ti... |
| `excludeBuiltIn`     | ❌  | boolean | true 時排除官方內建 Agent（由 Agent 市集租用而建立的鎖定實例）的資料，只留組織自建助理；「複製為自建」產生的副本屬自建。不帶或 false 時與未加此條件相同。                                                                                                                                    |
| `feedbackType`       | ❌  | array   | Multiple values may be separated by commas. \`like\`: Like ; \`dislike\`: Dislike;                                                                                                                                           |
| `hasError`           | ❌  | boolean |                                                                                                                                                                                                                              |
| `hasFeedback`        | ❌  | boolean |                                                                                                                                                                                                                              |
| `keyword`            | ❌  | string  | 關鍵字搜尋 (同時搜尋使用者訊息和機器人回答內容)                                                                                                                                                                                                    |
| `largeLanguageModel` | ❌  | string  | 篩選特定大型語言模型 (UUID)                                                                                                                                                                                                            |
| `page`               | ❌  | integer | A page number within the paginated result set.                                                                                                                                                                               |
| `pageSize`           | ❌  | integer | Number of results to return per page.                                                                                                                                                                                        |
| `source`             | ❌  | string  | 篩選記錄來源，逗號分隔；省略時同時回傳兩種來源。interactive = 使用者對話，scheduled = 排程執行。                                                                                                                                                                |
| `startDate`          | ❌  | string  | 開始日期（格式：YYYY-MM-DD，如：2025-01-01）                                                                                                                                                                                             |
| `startDatetime`      | ❌  | string  |                                                                                                                                                                                                                              |
| `tool`               | ❌  | string  |                                                                                                                                                                                                                              |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/records/?callerMember=example&chatbot=example&endDate=example&endDatetime=2025-01-01T00:00:00.000Z&errorType=example&excludeBuiltIn=true&feedbackType=example&hasError=true&hasFeedback=true&keyword=example&largeLanguageModel=example&page=1&pageSize=1&source=interactive&startDate=example&startDatetime=2025-01-01T00:00:00.000Z&tool=example" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/records/?callerMember=example&chatbot=example&endDate=example&endDatetime=2025-01-01T00:00:00.000Z&errorType=example&excludeBuiltIn=true&feedbackType=example&hasError=true&hasFeedback=true&keyword=example&largeLanguageModel=example&page=1&pageSize=1&source=interactive&startDate=example&startDatetime=2025-01-01T00:00:00.000Z&tool=example", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/records/?callerMember=example&chatbot=example&endDate=example&endDatetime=2025-01-01T00:00:00.000Z&errorType=example&excludeBuiltIn=true&feedbackType=example&hasError=true&hasFeedback=true&keyword=example&largeLanguageModel=example&page=1&pageSize=1&source=interactive&startDate=example&startDatetime=2025-01-01T00:00:00.000Z&tool=example"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/records/?callerMember=example&chatbot=example&endDate=example&endDatetime=2025-01-01T00:00:00.000Z&errorType=example&excludeBuiltIn=true&feedbackType=example&hasError=true&hasFeedback=true&keyword=example&largeLanguageModel=example&page=1&pageSize=1&source=interactive&startDate=example&startDatetime=2025-01-01T00:00:00.000Z&tool=example", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "count": integer
  "next"?: string (uri) // 非必填
  "previous"?: string (uri) // 非必填
  "results": [
    {
      "id": string (uuid)
      "senderName": string // 返回使用者訊息發送者的名稱
      "callerMemberId": string
      "callerMemberName": string
      "feedback": 
      {
        "id": string (uuid)
        "type": 
        {
        }
        "suggestion"?: string // 非必填
        "updatedAt": string (timestamp)
      }
      "inputMessage": string
      "condenseMessage": string // User message rewritten from the chat history and context.
      "outputMessage": string
      "faithfulnessScore": number (double) // Whether the chatbot reply is grounded in the knowledge base rather than made up.
      "displayFaithfulnessScore": integer
      "answerRelevancyScore": number (double) // Whether the chatbot reply is relevant to the user's question.
      "displayAnswerRelevancyScore": integer
      "contextPrecisionScore": number (double) // Whether the chatbot reply is relevant to the reference context.
      "displayContextPrecisionScore": integer
      "answerCorrectnessScore": number (double) // Whether the chatbot reply is correct (requires a ground-truth answer).
      "displayAnswerCorrectnessScore": integer
      "answerSimilarityScore": number (double) // Whether the chatbot reply is similar to the ground-truth answer.
      "displayAnswerSimilarityScore": integer
      "contextRecallScore": number (double) // Whether the chatbot reply recalls the relevant information from the reference context.
      "displayContextRecallScore": integer
      "replyTime": string
      "createdAt": string (timestamp)
      "error": string // Error message raised during execution.
      "errorType": // 可能有不同的類型
      string (enum: system, llm, embedding, reranker, vector_db, workflow, tool, timeout, client_interrupt, hook_blocked, evaluation, other) // Error source: system, LLM, embedding, reranker, and so on.

* `system` - System
* `llm` - LLM
* `embedding` - Embedding
* `reranker` - Reranker
* `vector_db` - Vector DB
* `workflow` - Workflow
* `tool` - Tool
* `timeout` - Timeout
* `client_interrupt` - Client Interrupt
* `hook_blocked` - Hook Blocked
* `evaluation` - Evaluation
* `other` - Other
      "processingTime": object // 回傳各個處理階段的時間統計，含 streaming_metrics waterfall
      "usage": 
      {
        "words":  // 字數統計
        {
          "input": integer // 使用者訊息字數（含圖片依張數折算的字數）
          "output": integer // AI 助理回覆字數（含圖片依張數折算的字數）
          "total": integer // input 與 output 的合計
        }
        "tokens":  // token 用量
        {
          "llm":  // LLM token 用量
          {
            "input": integer // LLM 輸入 token 數
            "output": integer // LLM 輸出 token 數
            "cacheCreationInputTokens": integer // 寫入提示快取的輸入 token 數
            "cacheReadInputTokens": integer // 從提示快取讀取的輸入 token 數
            "total": integer // input、output 與兩項快取 token 數的合計
          }
          "embedding": integer // 文字 embedding token 數
          "embeddingImage": integer // 圖片 embedding token 數
          "reranker": integer // 送進 reranker 的 chunk 數
        }
        "llmCallBreakdown": [ // 每次 LLM 呼叫的 token 明細，依呼叫時間排序；列表端點固定為空陣列，請改查詳情端點
          {
            "sequence": integer // 這次回覆中第幾次 LLM 呼叫，從 1 起算
            "inputTokens": integer // 該次呼叫的輸入 token 數
            "outputTokens": integer // 該次呼叫的輸出 token 數
            "cacheCreationInputTokens": integer // 該次呼叫寫入提示快取的 token 數
            "cacheReadInputTokens": integer // 該次呼叫讀取提示快取的 token 數
            "processingTimeSecs": number (double) // 該次呼叫耗時（秒）；未記錄時為 null
            "ttftSecs"?: number (double) // 該次呼叫的首字延遲（秒）；未記錄時為 null，部分舊紀錄不含此鍵 (非必填)
          }
        ]
      }
      "citationNodes": [
        {
          "id": string
          "text": string
          "chatbotFileId": string
          "fileName": string
          "url": string
        }
      ]
      "inputHookLogs": [
        {
          "id": string (uuid)
          "hook": string (uuid)
          "hookName": string
          "hookTypeLabel": string
          "hookAction": string
          "conversation": string (uuid)
          "message": string (uuid)
          "messageContent": string // Return the raw message text.
          "chatbotId": string
          "chatbotName": string
          "metadata": object
          "triggerPoint": string
          "createdAt": string (timestamp)
          "updatedAt": string (timestamp)
        }
      ]
      "outputHookLogs": [
        {
          "id": string (uuid)
          "hook": string (uuid)
          "hookName": string
          "hookTypeLabel": string
          "hookAction": string
          "conversation": string (uuid)
          "message": string (uuid)
          "messageContent": string // Return the raw message text.
          "chatbotId": string
          "chatbotName": string
          "metadata": object
          "triggerPoint": string
          "createdAt": string (timestamp)
          "updatedAt": string (timestamp)
        }
      ]
      "instructionId": string
      "llm": 
      {
        "id": string (uuid)
        "name": string
      }
      "effectiveMaxLlmOutputTokens": integer // max_tokens actually used for this reply, from Chatbot.custom_max_llm_output_tokens or LLM.max_tokens.
      "chatbot": 
      {
        "id": string (uuid)
        "name": string
      }
      "context": string
      "conversationId": string (uuid)
      "inboxId": string (uuid)
      "botMessageId": string (uuid)
      "userMessageId": string (uuid)
      "creditCosts": [ // 這則回覆依計費項目彙總的點數扣款。組織不是點數計費模式時為 null；組織是點數計費模式、但這則回覆沒有任何扣款交易時也為 null
        {
          "itemCode": string // 計費項目代碼
          "itemName": string // 計費項目名稱
          "category": string // 計費項目類別
          "credits": number (double) // 這則回覆在此計費項目扣除的點數合計
          "quantity": number (double) // 此計費項目的用量合計（單位依計費項目而定，例如 token 數）
          "unitPrice": number (double) // 扣款當下的單價快照；未記錄單價時為 null
          "count": integer // 合併進這一列的扣款筆數
        }
      ]
      "cacheSavedCredits": number (double) // Net credits saved by prompt caching for this reply; ``None`` outside credit mode.

Reuses the usage-statistics saving semantics (``compute_cache_saved_credits``)
on the reply's own billing batch, so the per-reply figure and the hourly
aggregate are defined by the same formula. The net value may be negative
(cache-creation premium exceeding read savings); the frontend hides
non-positive values by design.
      "trace": object // Return the round trace timeline for the detail view; ``None`` for legacy records.
      "llmRawRequest": object // Raw messages array sent to the LLM on the final round, including system prompt and memory
      "source": string // Origin discriminator for the unified /records/ response.
      "schedule": object // Shape parity with scheduled rows, which link their owning ChatbotSchedule here.
      "voiceOrigin": object // The voice session and turn that delegated this question here, if it was a delegation.
    }
  ]
}
```

**回應範例值**

```json
{
  "count": 123,
  "next": "http://api.example.org/accounts/?page=4",
  "previous": "http://api.example.org/accounts/?page=2",
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "senderName": "回應字串",
      "callerMemberId": "回應字串",
      "callerMemberName": "回應字串",
      "feedback": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": {},
        "suggestion": "回應字串",
        "updatedAt": "回應字串"
      },
      "inputMessage": "回應字串",
      "condenseMessage": "回應字串",
      "outputMessage": "回應字串",
      "faithfulnessScore": 456,
      "displayFaithfulnessScore": 456,
      "answerRelevancyScore": 456,
      "displayAnswerRelevancyScore": 456,
      "contextPrecisionScore": 456,
      "displayContextPrecisionScore": 456,
      "answerCorrectnessScore": 456,
      "displayAnswerCorrectnessScore": 456,
      "answerSimilarityScore": 456,
      "displayAnswerSimilarityScore": 456,
      "contextRecallScore": 456,
      "displayContextRecallScore": 456,
      "replyTime": "回應字串",
      "createdAt": "回應字串",
      "error": "回應字串",
      "errorType": "system",
      "processingTime": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "usage": {
        "words": {
          "input": 456,
          "output": 456,
          "total": 456
        },
        "tokens": {
          "llm": {
            "input": 456,
            "output": 456,
            "cacheCreationInputTokens": 456,
            "cacheReadInputTokens": 456,
            "total": 456
          },
          "embedding": 456,
          "embeddingImage": 456,
          "reranker": 456
        },
        "llmCallBreakdown": [
          {
            "sequence": 456,
            "inputTokens": 456,
            "outputTokens": 456,
            "cacheCreationInputTokens": 456,
            "cacheReadInputTokens": 456,
            "processingTimeSecs": 456,
            "ttftSecs": 456
          }
        ]
      },
      "citationNodes": [
        {
          "id": "回應字串",
          "text": "回應字串",
          "chatbotFileId": "回應字串",
          "fileName": "回應字串",
          "url": "回應字串"
        }
      ],
      "inputHookLogs": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "hook": "550e8400-e29b-41d4-a716-446655440000",
          "hookName": "回應字串",
          "hookTypeLabel": "回應字串",
          "hookAction": "回應字串",
          "conversation": "550e8400-e29b-41d4-a716-446655440000",
          "message": "550e8400-e29b-41d4-a716-446655440000",
          "messageContent": "回應字串",
          "chatbotId": "回應字串",
          "chatbotName": "回應字串",
          "metadata": null,
          "triggerPoint": "回應字串",
          "createdAt": "回應字串",
          "updatedAt": "回應字串"
        }
      ],
      "outputHookLogs": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "hook": "550e8400-e29b-41d4-a716-446655440000",
          "hookName": "回應字串",
          "hookTypeLabel": "回應字串",
          "hookAction": "回應字串",
          "conversation": "550e8400-e29b-41d4-a716-446655440000",
          "message": "550e8400-e29b-41d4-a716-446655440000",
          "messageContent": "回應字串",
          "chatbotId": "回應字串",
          "chatbotName": "回應字串",
          "metadata": null,
          "triggerPoint": "回應字串",
          "createdAt": "回應字串",
          "updatedAt": "回應字串"
        }
      ],
      "instructionId": "回應字串",
      "llm": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      },
      "effectiveMaxLlmOutputTokens": 456,
      "chatbot": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應字串"
      },
      "context": "回應字串",
      "conversationId": "550e8400-e29b-41d4-a716-446655440000",
      "inboxId": "550e8400-e29b-41d4-a716-446655440000",
      "botMessageId": "550e8400-e29b-41d4-a716-446655440000",
      "userMessageId": "550e8400-e29b-41d4-a716-446655440000",
      "creditCosts": [
        {
          "itemCode": "回應字串",
          "itemName": "回應字串",
          "category": "回應字串",
          "credits": 456,
          "quantity": 456,
          "unitPrice": 456,
          "count": 456
        }
      ],
      "cacheSavedCredits": 456,
      "trace": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "llmRawRequest": null,
      "source": "回應字串",
      "schedule": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      },
      "voiceOrigin": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "回應範例名稱",
        "description": "回應範例描述"
      }
    }
  ]
}
```

***

### 取得特定對話紀錄 <a href="#records-retrieve" id="records-retrieve"></a>

GET `/api/v1/records/{id}/`

#### 參數

| 參數名稱 | 必填 | 類型     | 說明                                             |
| ---- | -- | ------ | ---------------------------------------------- |
| `id` | ✅  | string | A UUID string identifying this Chatbot Record. |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/records/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/records/550e8400-e29b-41d4-a716-446655440000/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/records/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/records/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "senderName": string // 返回使用者訊息發送者的名稱
  "callerMemberId": string
  "callerMemberName": string
  "feedback": 
  {
    "id": string (uuid)
    "type": 
    {
    }
    "suggestion"?: string // 非必填
    "updatedAt": string (timestamp)
  }
  "inputMessage": string
  "condenseMessage": string // User message rewritten from the chat history and context.
  "outputMessage": string
  "faithfulnessScore": number (double) // Whether the chatbot reply is grounded in the knowledge base rather than made up.
  "displayFaithfulnessScore": integer
  "answerRelevancyScore": number (double) // Whether the chatbot reply is relevant to the user's question.
  "displayAnswerRelevancyScore": integer
  "contextPrecisionScore": number (double) // Whether the chatbot reply is relevant to the reference context.
  "displayContextPrecisionScore": integer
  "answerCorrectnessScore": number (double) // Whether the chatbot reply is correct (requires a ground-truth answer).
  "displayAnswerCorrectnessScore": integer
  "answerSimilarityScore": number (double) // Whether the chatbot reply is similar to the ground-truth answer.
  "displayAnswerSimilarityScore": integer
  "contextRecallScore": number (double) // Whether the chatbot reply recalls the relevant information from the reference context.
  "displayContextRecallScore": integer
  "replyTime": string
  "createdAt": string (timestamp)
  "error": string // Error message raised during execution.
  "errorType": // 可能有不同的類型
  string (enum: system, llm, embedding, reranker, vector_db, workflow, tool, timeout, client_interrupt, hook_blocked, evaluation, other) // Error source: system, LLM, embedding, reranker, and so on.

* `system` - System
* `llm` - LLM
* `embedding` - Embedding
* `reranker` - Reranker
* `vector_db` - Vector DB
* `workflow` - Workflow
* `tool` - Tool
* `timeout` - Timeout
* `client_interrupt` - Client Interrupt
* `hook_blocked` - Hook Blocked
* `evaluation` - Evaluation
* `other` - Other
  "processingTime": object // 回傳各個處理階段的時間統計，含 streaming_metrics waterfall
  "usage": 
  {
    "words":  // 字數統計
    {
      "input": integer // 使用者訊息字數（含圖片依張數折算的字數）
      "output": integer // AI 助理回覆字數（含圖片依張數折算的字數）
      "total": integer // input 與 output 的合計
    }
    "tokens":  // token 用量
    {
      "llm":  // LLM token 用量
      {
        "input": integer // LLM 輸入 token 數
        "output": integer // LLM 輸出 token 數
        "cacheCreationInputTokens": integer // 寫入提示快取的輸入 token 數
        "cacheReadInputTokens": integer // 從提示快取讀取的輸入 token 數
        "total": integer // input、output 與兩項快取 token 數的合計
      }
      "embedding": integer // 文字 embedding token 數
      "embeddingImage": integer // 圖片 embedding token 數
      "reranker": integer // 送進 reranker 的 chunk 數
    }
    "llmCallBreakdown": [ // 每次 LLM 呼叫的 token 明細，依呼叫時間排序；列表端點固定為空陣列，請改查詳情端點
      {
        "sequence": integer // 這次回覆中第幾次 LLM 呼叫，從 1 起算
        "inputTokens": integer // 該次呼叫的輸入 token 數
        "outputTokens": integer // 該次呼叫的輸出 token 數
        "cacheCreationInputTokens": integer // 該次呼叫寫入提示快取的 token 數
        "cacheReadInputTokens": integer // 該次呼叫讀取提示快取的 token 數
        "processingTimeSecs": number (double) // 該次呼叫耗時（秒）；未記錄時為 null
        "ttftSecs"?: number (double) // 該次呼叫的首字延遲（秒）；未記錄時為 null，部分舊紀錄不含此鍵 (非必填)
      }
    ]
  }
  "citationNodes": [
    {
      "id": string
      "text": string
      "chatbotFileId": string
      "fileName": string
      "url": string
    }
  ]
  "inputHookLogs": [
    {
      "id": string (uuid)
      "hook": string (uuid)
      "hookName": string
      "hookTypeLabel": string
      "hookAction": string
      "conversation": string (uuid)
      "message": string (uuid)
      "messageContent": string // Return the raw message text.
      "chatbotId": string
      "chatbotName": string
      "metadata": object
      "triggerPoint": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "outputHookLogs": [
    {
      "id": string (uuid)
      "hook": string (uuid)
      "hookName": string
      "hookTypeLabel": string
      "hookAction": string
      "conversation": string (uuid)
      "message": string (uuid)
      "messageContent": string // Return the raw message text.
      "chatbotId": string
      "chatbotName": string
      "metadata": object
      "triggerPoint": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "instructionId": string
  "llm": 
  {
    "id": string (uuid)
    "name": string
  }
  "effectiveMaxLlmOutputTokens": integer // max_tokens actually used for this reply, from Chatbot.custom_max_llm_output_tokens or LLM.max_tokens.
  "chatbot": 
  {
    "id": string (uuid)
    "name": string
  }
  "context": string
  "conversationId": string (uuid)
  "inboxId": string (uuid)
  "botMessageId": string (uuid)
  "userMessageId": string (uuid)
  "creditCosts": [ // 這則回覆依計費項目彙總的點數扣款。組織不是點數計費模式時為 null；組織是點數計費模式、但這則回覆沒有任何扣款交易時也為 null
    {
      "itemCode": string // 計費項目代碼
      "itemName": string // 計費項目名稱
      "category": string // 計費項目類別
      "credits": number (double) // 這則回覆在此計費項目扣除的點數合計
      "quantity": number (double) // 此計費項目的用量合計（單位依計費項目而定，例如 token 數）
      "unitPrice": number (double) // 扣款當下的單價快照；未記錄單價時為 null
      "count": integer // 合併進這一列的扣款筆數
    }
  ]
  "cacheSavedCredits": number (double) // Net credits saved by prompt caching for this reply; ``None`` outside credit mode.

Reuses the usage-statistics saving semantics (``compute_cache_saved_credits``)
on the reply's own billing batch, so the per-reply figure and the hourly
aggregate are defined by the same formula. The net value may be negative
(cache-creation premium exceeding read savings); the frontend hides
non-positive values by design.
  "trace": object // Return the round trace timeline for the detail view; ``None`` for legacy records.
  "llmRawRequest": object // Raw messages array sent to the LLM on the final round, including system prompt and memory
  "source": string // Origin discriminator for the unified /records/ response.
  "schedule": object // Shape parity with scheduled rows, which link their owning ChatbotSchedule here.
  "voiceOrigin": object // The voice session and turn that delegated this question here, if it was a delegation.
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "senderName": "回應字串",
  "callerMemberId": "回應字串",
  "callerMemberName": "回應字串",
  "feedback": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": {},
    "suggestion": "回應字串",
    "updatedAt": "回應字串"
  },
  "inputMessage": "回應字串",
  "condenseMessage": "回應字串",
  "outputMessage": "回應字串",
  "faithfulnessScore": 456,
  "displayFaithfulnessScore": 456,
  "answerRelevancyScore": 456,
  "displayAnswerRelevancyScore": 456,
  "contextPrecisionScore": 456,
  "displayContextPrecisionScore": 456,
  "answerCorrectnessScore": 456,
  "displayAnswerCorrectnessScore": 456,
  "answerSimilarityScore": 456,
  "displayAnswerSimilarityScore": 456,
  "contextRecallScore": 456,
  "displayContextRecallScore": 456,
  "replyTime": "回應字串",
  "createdAt": "回應字串",
  "error": "回應字串",
  "errorType": "system",
  "processingTime": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "usage": {
    "words": {
      "input": 456,
      "output": 456,
      "total": 456
    },
    "tokens": {
      "llm": {
        "input": 456,
        "output": 456,
        "cacheCreationInputTokens": 456,
        "cacheReadInputTokens": 456,
        "total": 456
      },
      "embedding": 456,
      "embeddingImage": 456,
      "reranker": 456
    },
    "llmCallBreakdown": [
      {
        "sequence": 456,
        "inputTokens": 456,
        "outputTokens": 456,
        "cacheCreationInputTokens": 456,
        "cacheReadInputTokens": 456,
        "processingTimeSecs": 456,
        "ttftSecs": 456
      }
    ]
  },
  "citationNodes": [
    {
      "id": "回應字串",
      "text": "回應字串",
      "chatbotFileId": "回應字串",
      "fileName": "回應字串",
      "url": "回應字串"
    }
  ],
  "inputHookLogs": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "hook": "550e8400-e29b-41d4-a716-446655440000",
      "hookName": "回應字串",
      "hookTypeLabel": "回應字串",
      "hookAction": "回應字串",
      "conversation": "550e8400-e29b-41d4-a716-446655440000",
      "message": "550e8400-e29b-41d4-a716-446655440000",
      "messageContent": "回應字串",
      "chatbotId": "回應字串",
      "chatbotName": "回應字串",
      "metadata": null,
      "triggerPoint": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "outputHookLogs": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "hook": "550e8400-e29b-41d4-a716-446655440000",
      "hookName": "回應字串",
      "hookTypeLabel": "回應字串",
      "hookAction": "回應字串",
      "conversation": "550e8400-e29b-41d4-a716-446655440000",
      "message": "550e8400-e29b-41d4-a716-446655440000",
      "messageContent": "回應字串",
      "chatbotId": "回應字串",
      "chatbotName": "回應字串",
      "metadata": null,
      "triggerPoint": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "instructionId": "回應字串",
  "llm": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "effectiveMaxLlmOutputTokens": 456,
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "context": "回應字串",
  "conversationId": "550e8400-e29b-41d4-a716-446655440000",
  "inboxId": "550e8400-e29b-41d4-a716-446655440000",
  "botMessageId": "550e8400-e29b-41d4-a716-446655440000",
  "userMessageId": "550e8400-e29b-41d4-a716-446655440000",
  "creditCosts": [
    {
      "itemCode": "回應字串",
      "itemName": "回應字串",
      "category": "回應字串",
      "credits": 456,
      "quantity": 456,
      "unitPrice": 456,
      "count": 456
    }
  ],
  "cacheSavedCredits": 456,
  "trace": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "llmRawRequest": null,
  "source": "回應字串",
  "schedule": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "voiceOrigin": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  }
}
```

**狀態碼: 404 - 找不到指定的對話記錄**

***

### 建立對話紀錄匯出請求 <a href="#records-export-excel-requests-create" id="records-export-excel-requests-create"></a>

POST `/api/v1/records/export-excel-requests/`

#### 請求內容

**請求參數**

| 欄位                 | 類型                 | 必填 | 說明                                                                                        |
| ------------------ | ------------------ | -- | ----------------------------------------------------------------------------------------- |
| chatbot            | string             | 否  | 指定要匯出的 Chatbot UUID，支援逗號分隔多個 UUID。留空則匯出組織內所有有權限的 Chatbot。                                 |
| chatbotId          | string (uuid)      | 否  | 指定要匯出的 Chatbot UUID（chatbot 的別名，僅支援單個 UUID）。                                              |
| keyword            | string             | 否  | 過濾包含特定關鍵字的對話記錄（搜尋用戶訊息和機器人回覆）。                                                             |
| largeLanguageModel | string             | 否  | 指定要匯出的大型語言模型 UUID，支援逗號分隔多個 UUID。                                                          |
| startDate          | string (date)      | 否  | 開始日期 (YYYY-MM-DD)，包含當天。                                                                   |
| endDate            | string (date)      | 否  | 結束日期 (YYYY-MM-DD)，包含當天。                                                                   |
| startDatetime      | string (timestamp) | 否  | 精確開始時間（ISO 8601，包含該時間點），與列表下鑽篩選同語意。                                                       |
| endDatetime        | string (timestamp) | 否  | 精確結束時間（ISO 8601，不包含該時間點），與列表下鑽篩選同語意。                                                      |
| hasError           | boolean            | 否  | 過濾是否有錯誤的紀錄（true 僅含有錯誤、false 僅含無錯誤）。                                                       |
| errorType          | string             | 否  | 過濾錯誤類型，支援逗號分隔多選（OR 邏輯），值域同對話紀錄列表。                                                         |
| hasFeedback        | boolean            | 否  | 過濾是否有使用者評價（true 僅含有讚/倒讚、false 僅含無評價）。                                                     |
| feedbackType       | string             | 否  | 過濾使用者評價類型（like / dislike），支援逗號分隔多選（OR 邏輯）。                                                |
| callerMember       | string             | 否  | 過濾發話成員 UUID，支援逗號分隔多選（OR 邏輯）。                                                              |
| tool               | string (uuid)      | 否  | 過濾呼叫過該工具的問答（工具 UUID，含平台內建工具；執行失敗也算）。                                                      |
| excludeBuiltIn     | boolean            | 否  | true 時排除官方內建 Agent（由 Agent 市集租用而建立的鎖定實例）的資料，只留組織自建助理；「複製為自建」產生的副本屬自建。不帶或 false 時與未加此條件相同。 |

**請求結構範例**

```typescript
{
  "chatbot"?: string // 指定要匯出的 Chatbot UUID，支援逗號分隔多個 UUID。留空則匯出組織內所有有權限的 Chatbot。 (非必填)
  "chatbotId"?: string (uuid) // 指定要匯出的 Chatbot UUID（chatbot 的別名，僅支援單個 UUID）。 (非必填)
  "keyword"?: string // 過濾包含特定關鍵字的對話記錄（搜尋用戶訊息和機器人回覆）。 (非必填)
  "largeLanguageModel"?: string // 指定要匯出的大型語言模型 UUID，支援逗號分隔多個 UUID。 (非必填)
  "startDate"?: string (date) // 開始日期 (YYYY-MM-DD)，包含當天。 (非必填)
  "endDate"?: string (date) // 結束日期 (YYYY-MM-DD)，包含當天。 (非必填)
  "startDatetime"?: string (timestamp) // 精確開始時間（ISO 8601，包含該時間點），與列表下鑽篩選同語意。 (非必填)
  "endDatetime"?: string (timestamp) // 精確結束時間（ISO 8601，不包含該時間點），與列表下鑽篩選同語意。 (非必填)
  "hasError"?: boolean // 過濾是否有錯誤的紀錄（true 僅含有錯誤、false 僅含無錯誤）。 (非必填)
  "errorType"?: string // 過濾錯誤類型，支援逗號分隔多選（OR 邏輯），值域同對話紀錄列表。 (非必填)
  "hasFeedback"?: boolean // 過濾是否有使用者評價（true 僅含有讚/倒讚、false 僅含無評價）。 (非必填)
  "feedbackType"?: string // 過濾使用者評價類型（like / dislike），支援逗號分隔多選（OR 邏輯）。 (非必填)
  "callerMember"?: string // 過濾發話成員 UUID，支援逗號分隔多選（OR 邏輯）。 (非必填)
  "tool"?: string (uuid) // 過濾呼叫過該工具的問答（工具 UUID，含平台內建工具；執行失敗也算）。 (非必填)
  "excludeBuiltIn"?: boolean // true 時排除官方內建 Agent（由 Agent 市集租用而建立的鎖定實例）的資料，只留組織自建助理；「複製為自建」產生的副本屬自建。不帶或 false 時與未加此條件相同。 (非必填)
}
```

**請求範例值**

```json
{
  "chatbot": "範例字串",
  "chatbotId": "550e8400-e29b-41d4-a716-446655440000",
  "keyword": "範例字串",
  "largeLanguageModel": "範例字串",
  "startDate": "範例字串",
  "endDate": "範例字串",
  "startDatetime": "範例字串",
  "endDatetime": "範例字串",
  "hasError": true,
  "errorType": "範例字串",
  "hasFeedback": true,
  "feedbackType": "範例字串",
  "callerMember": "範例字串",
  "tool": "550e8400-e29b-41d4-a716-446655440000",
  "excludeBuiltIn": true
}
```

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/records/export-excel-requests/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chatbot": "範例字串",
    "chatbotId": "550e8400-e29b-41d4-a716-446655440000",
    "keyword": "範例字串",
    "largeLanguageModel": "範例字串",
    "startDate": "範例字串",
    "endDate": "範例字串",
    "startDatetime": "範例字串",
    "endDatetime": "範例字串",
    "hasError": true,
    "errorType": "範例字串",
    "hasFeedback": true,
    "feedbackType": "範例字串",
    "callerMember": "範例字串",
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "excludeBuiltIn": true
  }'

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
};

// 請求內容 (payload)
const data = {
    "chatbot": "範例字串",
    "chatbotId": "550e8400-e29b-41d4-a716-446655440000",
    "keyword": "範例字串",
    "largeLanguageModel": "範例字串",
    "startDate": "範例字串",
    "endDate": "範例字串",
    "startDatetime": "範例字串",
    "endDatetime": "範例字串",
    "hasError": true,
    "errorType": "範例字串",
    "hasFeedback": true,
    "feedbackType": "範例字串",
    "callerMember": "範例字串",
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "excludeBuiltIn": true
  };

axios.post("https://api.maiagent.ai/api/v1/records/export-excel-requests/", data, config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/records/export-excel-requests/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "chatbot": "範例字串",
    "chatbotId": "550e8400-e29b-41d4-a716-446655440000",
    "keyword": "範例字串",
    "largeLanguageModel": "範例字串",
    "startDate": "範例字串",
    "endDate": "範例字串",
    "startDatetime": "範例字串",
    "endDatetime": "範例字串",
    "hasError": True,
    "errorType": "範例字串",
    "hasFeedback": True,
    "feedbackType": "範例字串",
    "callerMember": "範例字串",
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "excludeBuiltIn": True
}

response = requests.post(url, json=data, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->post("https://api.maiagent.ai/api/v1/records/export-excel-requests/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'chatbot' => '範例字串',
            'chatbotId' => '550e8400-e29b-41d4-a716-446655440000',
            'keyword' => '範例字串',
            'largeLanguageModel' => '範例字串',
            'startDate' => '範例字串',
            'endDate' => '範例字串',
            'startDatetime' => '範例字串',
            'endDatetime' => '範例字串',
            'hasError' => true,
            'errorType' => '範例字串',
            'hasFeedback' => true,
            'feedbackType' => '範例字串',
            'callerMember' => '範例字串',
            'tool' => '550e8400-e29b-41d4-a716-446655440000',
            'excludeBuiltIn' => true
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "userEmail": string (email)
  "recordType":  // Which monitoring list this export was requested from. Text exports read filter_params with the text record filters, voice exports with the voice session filters.

* `text` - Text records
* `voice` - Voice sessions
  {
  }
  "chatbotId": string (uuid) // 指定要匯出的 Chatbot（已棄用，請使用 chatbot_ids）
  "chatbotIds": object // 指定要匯出的 Chatbot UUID 列表，留空則匯出組織內所有有權限的 Chatbot
  "startDate": string (date) // 匯出記錄的開始日期（包含）
  "endDate": string (date) // 匯出記錄的結束日期（包含）
  "status": 
  {
  }
  "statusDisplay": string
  "fileUrl": string // 返回檔案 URL（永久有效）
  "fileSize": integer // 檔案大小（bytes）
  "recordCount": integer // 匯出的記錄總數
  "errorMessage": string
  "processingDurationSeconds": number (double) // 計算處理時長（秒）
  "createdAt": string (timestamp)
  "startedAt": string (timestamp)
  "completedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "userEmail": "response@example.com",
  "recordType": {},
  "chatbotId": "550e8400-e29b-41d4-a716-446655440000",
  "chatbotIds": null,
  "startDate": "回應字串",
  "endDate": "回應字串",
  "status": {},
  "statusDisplay": "回應字串",
  "fileUrl": "回應字串",
  "fileSize": 456,
  "recordCount": 456,
  "errorMessage": "回應字串",
  "processingDurationSeconds": 456,
  "createdAt": "回應字串",
  "startedAt": "回應字串",
  "completedAt": "回應字串"
}
```

***

### 取得對話紀錄匯出狀態 <a href="#records-export-excel-requests-retrieve2" id="records-export-excel-requests-retrieve2"></a>

GET `/api/v1/records/export-excel-requests/{exportId}/`

#### 參數

| 參數名稱       | 必填 | 類型     | 說明 |
| ---------- | -- | ------ | -- |
| `exportId` | ✅  | string |    |

#### 程式碼範例

{% tabs %}
{% tab title="Shell/Bash" %}

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/records/export-excel-requests/{exportId}/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# 請確認在執行前替換 YOUR_API_KEY 並核對請求資料。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY'
  }
};

axios.get("https://api.maiagent.ai/api/v1/records/export-excel-requests/{exportId}/", config)
  .then(response => {
    console.log('成功取得回應:');
    console.log(response.data);
  })
  .catch(error => {
    console.error('請求發生錯誤:');
    console.error(error.response?.data || error.message);
  });
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.maiagent.ai/api/v1/records/export-excel-requests/{exportId}/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}


response = requests.get(url, headers=headers)
try:
    print("成功取得回應:")
    print(response.json())
except Exception as e:
    print("請求發生錯誤:", e)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client();

try {
    $response = $client->get("https://api.maiagent.ai/api/v1/records/export-excel-requests/{exportId}/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "senderName": string // 返回使用者訊息發送者的名稱
  "callerMemberId": string
  "callerMemberName": string
  "inputMessage": string
  "outputMessage": string
  "chatbot": 
  {
    "id": string (uuid)
    "name": string
  }
  "condenseMessage": string // User message rewritten from the chat history and context.
  "feedback": 
  {
    "id": string (uuid)
    "type": 
    {
    }
    "suggestion"?: string // 非必填
    "updatedAt": string (timestamp)
  }
  "displayFaithfulnessScore": integer
  "displayAnswerRelevancyScore": integer
  "displayContextPrecisionScore": integer
  "displayAnswerCorrectnessScore": integer
  "displayAnswerSimilarityScore": integer
  "displayContextRecallScore": integer
  "replyTime": string
  "processingTime": object // 回傳列表頁處理時間統計，與詳情頁算式一致但不含 streaming_metrics waterfall
  "usage": 
  {
    "words":  // 字數統計
    {
      "input": integer // 使用者訊息字數（含圖片依張數折算的字數）
      "output": integer // AI 助理回覆字數（含圖片依張數折算的字數）
      "total": integer // input 與 output 的合計
    }
    "tokens":  // token 用量
    {
      "llm":  // LLM token 用量
      {
        "input": integer // LLM 輸入 token 數
        "output": integer // LLM 輸出 token 數
        "cacheCreationInputTokens": integer // 寫入提示快取的輸入 token 數
        "cacheReadInputTokens": integer // 從提示快取讀取的輸入 token 數
        "total": integer // input、output 與兩項快取 token 數的合計
      }
      "embedding": integer // 文字 embedding token 數
      "embeddingImage": integer // 圖片 embedding token 數
      "reranker": integer // 送進 reranker 的 chunk 數
    }
    "llmCallBreakdown": [ // 每次 LLM 呼叫的 token 明細，依呼叫時間排序；列表端點固定為空陣列，請改查詳情端點
      {
        "sequence": integer // 這次回覆中第幾次 LLM 呼叫，從 1 起算
        "inputTokens": integer // 該次呼叫的輸入 token 數
        "outputTokens": integer // 該次呼叫的輸出 token 數
        "cacheCreationInputTokens": integer // 該次呼叫寫入提示快取的 token 數
        "cacheReadInputTokens": integer // 該次呼叫讀取提示快取的 token 數
        "processingTimeSecs": number (double) // 該次呼叫耗時（秒）；未記錄時為 null
        "ttftSecs"?: number (double) // 該次呼叫的首字延遲（秒）；未記錄時為 null，部分舊紀錄不含此鍵 (非必填)
      }
    ]
  }
  "llm": 
  {
    "id": string (uuid)
    "name": string
  }
  "createdAt": string (timestamp)
  "conversationId": string (uuid)
  "errorType": // 可能有不同的類型
  string (enum: system, llm, embedding, reranker, vector_db, workflow, tool, timeout, client_interrupt, hook_blocked, evaluation, other) // Error source: system, LLM, embedding, reranker, and so on.

* `system` - System
* `llm` - LLM
* `embedding` - Embedding
* `reranker` - Reranker
* `vector_db` - Vector DB
* `workflow` - Workflow
* `tool` - Tool
* `timeout` - Timeout
* `client_interrupt` - Client Interrupt
* `hook_blocked` - Hook Blocked
* `evaluation` - Evaluation
* `other` - Other
  "creditCosts": [ // 這則回覆依計費項目彙總的點數扣款。組織不是點數計費模式時為 null；組織是點數計費模式、但這則回覆沒有任何扣款交易時也為 null
    {
      "itemCode": string // 計費項目代碼
      "itemName": string // 計費項目名稱
      "category": string // 計費項目類別
      "credits": number (double) // 這則回覆在此計費項目扣除的點數合計
      "quantity": number (double) // 此計費項目的用量合計（單位依計費項目而定，例如 token 數）
      "unitPrice": number (double) // 扣款當下的單價快照；未記錄單價時為 null
      "count": integer // 合併進這一列的扣款筆數
    }
  ]
  "source": string // Origin discriminator for the unified /records/ response.
  "schedule": object // Shape parity with scheduled rows, which link their owning ChatbotSchedule here.
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "senderName": "回應字串",
  "callerMemberId": "回應字串",
  "callerMemberName": "回應字串",
  "inputMessage": "回應字串",
  "outputMessage": "回應字串",
  "chatbot": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "condenseMessage": "回應字串",
  "feedback": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": {},
    "suggestion": "回應字串",
    "updatedAt": "回應字串"
  },
  "displayFaithfulnessScore": 456,
  "displayAnswerRelevancyScore": 456,
  "displayContextPrecisionScore": 456,
  "displayAnswerCorrectnessScore": 456,
  "displayAnswerSimilarityScore": 456,
  "displayContextRecallScore": 456,
  "replyTime": "回應字串",
  "processingTime": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "usage": {
    "words": {
      "input": 456,
      "output": 456,
      "total": 456
    },
    "tokens": {
      "llm": {
        "input": 456,
        "output": 456,
        "cacheCreationInputTokens": 456,
        "cacheReadInputTokens": 456,
        "total": 456
      },
      "embedding": 456,
      "embeddingImage": 456,
      "reranker": 456
    },
    "llmCallBreakdown": [
      {
        "sequence": 456,
        "inputTokens": 456,
        "outputTokens": 456,
        "cacheCreationInputTokens": 456,
        "cacheReadInputTokens": 456,
        "processingTimeSecs": 456,
        "ttftSecs": 456
      }
    ]
  },
  "llm": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "createdAt": "回應字串",
  "conversationId": "550e8400-e29b-41d4-a716-446655440000",
  "errorType": "system",
  "creditCosts": [
    {
      "itemCode": "回應字串",
      "itemName": "回應字串",
      "category": "回應字串",
      "credits": 456,
      "quantity": 456,
      "unitPrice": 456,
      "count": 456
    }
  ],
  "source": "回應字串",
  "schedule": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  }
}
```

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.maiagent.ai/api/api-reference/dui-hua-he-xun-xi.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
