> 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/lian-luo-ren.md).

# 聯絡人

### 列出聯絡人 <a href="#contacts-list" id="contacts-list"></a>

GET `/api/v1/contacts/`

#### 參數

| 參數名稱         | 必填 | 類型      | 說明                                             |
| ------------ | -- | ------- | ---------------------------------------------- |
| `channels`   | ❌  | array   | Multiple values may be separated by commas.    |
| `externalId` | ❌  | string  | 外部使用者 ID（完全相符）                                 |
| `inbox`      | ❌  | string  | Deprecated: Use inboxes instead                |
| `inboxes`    | ❌  | string  | 對話平台 ID (用於過濾特定 inbox 的聯絡人)                    |
| `page`       | ❌  | integer | A page number within the paginated result set. |
| `pageSize`   | ❌  | integer | Number of results to return per page.          |
| `query`      | ❌  | string  | 姓名或來源ID搜尋                                      |
| `search`     | ❌  | string  | 全文搜尋                                           |
| `tags`       | ❌  | array   | Multiple values may be separated by commas.    |

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/contacts/?channels=example&externalId=example&inbox=550e8400-e29b-41d4-a716-446655440000&inboxes=example&page=1&pageSize=1&query=example&search=example&tags=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/contacts/?channels=example&externalId=example&inbox=550e8400-e29b-41d4-a716-446655440000&inboxes=example&page=1&pageSize=1&query=example&search=example&tags=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/contacts/?channels=example&externalId=example&inbox=550e8400-e29b-41d4-a716-446655440000&inboxes=example&page=1&pageSize=1&query=example&search=example&tags=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/contacts/?channels=example&externalId=example&inbox=550e8400-e29b-41d4-a716-446655440000&inboxes=example&page=1&pageSize=1&query=example&search=example&tags=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)
      "inboxes"?: [ // 非必填
        {
          "id": string (uuid)
          "name": string
        }
      ]
      "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
      {
        "id": string (uuid)
        "name": string
      }
      "name": string
      "avatar"?: // 可能有不同的類型 (非必填)
      string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
      "phoneNumber"?: string // 非必填
      "email"?: // 可能有不同的類型 (非必填)
      string (email) // 非必填
      "sourceId"?: string // 非必填
      "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
      "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
      "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
        object
      ]
      "apiCredentials": [ // 聯絡人的 API 認證憑證列表
        object
      ]
      "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
        object
      ]
      "tags": [
        {
          "id": string (uuid)
          "name": string
          "createdAt": string (timestamp)
          "updatedAt": string (timestamp)
        }
      ]
      "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
}
```

**回應範例值**

```json
{
  "count": 123,
  "next": "http://api.example.org/accounts/?page=4",
  "previous": "http://api.example.org/accounts/?page=2",
  "results": [
    [
      {
        "id": "user1_uuid",
        "inboxes": [
          {
            "id": "inbox_uuid",
            "name": "inbox_name"
          }
        ],
        "name": "user1",
        "avatar": "",
        "sourceId": null,
        "queryMetadata": null,
        "createdAt": "1751875361000",
        "updatedAt": "1751875361000"
      },
      {
        "id": "user2_uuid",
        "inboxes": [
          {
            "id": "inbox_uuid",
            "name": "inbox_name"
          }
        ],
        "name": "user2",
        "avatar": "avatar_url",
        "sourceId": "self defined source id",
        "queryMetadata": {
          "knowledgeBases": [
            {
              "knowledgeBaseId": "5f8c6a99-5515-43aa-8e83-fdeea327a3a2",
              "hasUserSelectedAll": true
            }
          ],
          "labelRelations": {
            "operator": "OR",
            "conditions": [
              {
                "labelId": "957998f9-1824-4872-becd-b7f8a7962896"
              }
            ]
          }
        },
        "createdAt": "1751875400000",
        "updatedAt": "1751875400000"
      }
    ]
  ]
}
```

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

***

### 建立聯絡人 <a href="#contacts-create" id="contacts-create"></a>

POST `/api/v1/contacts/`

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/contacts/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inboxes": [
      {
        "id": "inbox_uuid"
      }
    ],
    "name": "user1",
    "avatar": "",
    "phoneNumber": 912345678,
    "email": "user1@example.com",
    "sourceId": "self defined source id",
    "queryMetadata": {
      "knowledgeBases": [
        {
          "knowledgeBaseId": "5f8c6a99-5515-43aa-8e83-fdeea327a3a2",
          "hasUserSelectedAll": true
        }
      ],
      "labelRelations": {
        "operator": "OR",
        "conditions": [
          {
            "labelId": "957998f9-1824-4872-becd-b7f8a7962896"
          }
        ]
      }
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VIP"
      },
      {
        "key": "偏好語言",
        "value": "繁體中文"
      }
    ]
  }'

# 請確認在執行前替換 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 = {
    "inboxes": [
      {
        "id": "inbox_uuid"
      }
    ],
    "name": "user1",
    "avatar": "",
    "phoneNumber": 912345678,
    "email": "user1@example.com",
    "sourceId": "self defined source id",
    "queryMetadata": {
      "knowledgeBases": [
        {
          "knowledgeBaseId": "5f8c6a99-5515-43aa-8e83-fdeea327a3a2",
          "hasUserSelectedAll": true
        }
      ],
      "labelRelations": {
        "operator": "OR",
        "conditions": [
          {
            "labelId": "957998f9-1824-4872-becd-b7f8a7962896"
          }
        ]
      }
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VIP"
      },
      {
        "key": "偏好語言",
        "value": "繁體中文"
      }
    ]
  };

axios.post("https://api.maiagent.ai/api/v1/contacts/", 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/contacts/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "inboxes": [
        {
            "id": "inbox_uuid"
        }
    ],
    "name": "user1",
    "avatar": "",
    "phoneNumber": 912345678,
    "email": "user1@example.com",
    "sourceId": "self defined source id",
    "queryMetadata": {
        "knowledgeBases": [
            {
                "knowledgeBaseId": "5f8c6a99-5515-43aa-8e83-fdeea327a3a2",
                "hasUserSelectedAll": True
            }
        ],
        "labelRelations": {
            "operator": "OR",
            "conditions": [
                {
                    "labelId": "957998f9-1824-4872-becd-b7f8a7962896"
                }
            ]
        }
    },
    "metadata": [
        {
            "key": "客戶等級",
            "value": "VIP"
        },
        {
            "key": "偏好語言",
            "value": "繁體中文"
        }
    ]
}

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/contacts/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'inboxes' => [
                [
                    'id' => 'inbox_uuid'
                ]
            ],
            'name' => 'user1',
            'avatar' => '',
            'phoneNumber' => 912345678,
            'email' => 'user1@example.com',
            'sourceId' => 'self defined source id',
            'queryMetadata' => [
                'knowledgeBases' => [
                    [
                        'knowledgeBaseId' => '5f8c6a99-5515-43aa-8e83-fdeea327a3a2',
                        'hasUserSelectedAll' => true
                    ]
                ],
                'labelRelations' => [
                    'operator' => 'OR',
                    'conditions' => [
                        [
                            'labelId' => '957998f9-1824-4872-becd-b7f8a7962896'
                        ]
                    ]
                ]
            ],
            'metadata' => [
                [
                    'key' => '客戶等級',
                    'value' => 'VIP'
                ],
                [
                    'key' => '偏好語言',
                    'value' => '繁體中文'
                ]
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "user1_uuid",
  "inboxes": [
    {
      "id": "inbox_uuid",
      "name": "inbox_name"
    }
  ],
  "name": "user1",
  "avatar": "",
  "phoneNumber": 912345678,
  "email": "user1@example.com",
  "sourceId": null,
  "queryMetadata": null,
  "createdAt": "1751875361000",
  "updatedAt": "1751875361000"
}
```

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

***

### 取得聯絡人詳情 <a href="#contacts-retrieve" id="contacts-retrieve"></a>

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

#### 參數

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

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/contacts/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/contacts/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/contacts/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/contacts/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)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "user1_uuid",
  "inboxes": [
    {
      "id": "inbox_uuid",
      "name": "inbox_name"
    }
  ],
  "name": "user1",
  "avatar": "",
  "phoneNumber": 912345678,
  "email": "user1@example.com",
  "sourceId": null,
  "queryMetadata": null,
  "createdAt": "1751875361000",
  "updatedAt": "1751875361000"
}
```

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

***

### 更新聯絡人 <a href="#contacts-update" id="contacts-update"></a>

PUT `/api/v1/contacts/{id}/`

#### 參數

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

#### 請求內容

**請求參數**

| 欄位                                      | 類型                     | 必填 | 說明                                                                                                                                                                    |
| --------------------------------------- | ---------------------- | -- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name                                    | string                 | 否  | 聯絡人姓名                                                                                                                                                                 |
| inboxes                                 | array\[object]         | 否  | 對話平台列表（新版格式）                                                                                                                                                          |
| inbox                                   | object                 | 否  | 單一對話平台（舊版格式，向前相容）                                                                                                                                                     |
| inbox.id                                | string (uuid)          | 是  | 對話平台 ID                                                                                                                                                               |
| avatar                                  | string                 | 否  | 頭像URL                                                                                                                                                                 |
| phoneNumber                             | string                 | 否  | 聯絡人電話號碼                                                                                                                                                               |
| email                                   | string (email)         | 否  | 聯絡人電子信箱                                                                                                                                                               |
| sourceId                                | string                 | 否  | 來源ID                                                                                                                                                                  |
| queryMetadata                           | object                 | 否  | 查詢元資料（Query Metadata），控制可查詢的知識範圍。未提供或 null＝未設定（不限制）；空物件 {}＝視同不限制（全選），並非無權限；knowledgeBases 為空陣列或 null＝全部不可查（無權限）；labelRelations.conditions 為空陣列＝不做標籤過濾（並非無權限）。詳見本端點說明。 |
| 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                                | array\[object]         | 否  | 自訂聯絡人屬性列表                                                                                                                                                             |

**請求結構範例**

```typescript
{
  "name"?: string // 聯絡人姓名 (非必填)
  "inboxes"?: [ // 對話平台列表（新版格式） (非必填)
    {
      "id": string (uuid) // 對話平台 ID
    }
  ]
  "inbox"?: { // 單一對話平台（舊版格式，向前相容） (非必填)
  {
    "id": string (uuid) // 對話平台 ID
  }
  }
  "avatar"?: string // 頭像URL (非必填)
  "phoneNumber"?: string // 聯絡人電話號碼 (非必填)
  "email"?: string (email) // 聯絡人電子信箱 (非必填)
  "sourceId"?: string // 來源ID (非必填)
  "queryMetadata"?: { // 查詢元資料（Query Metadata），控制可查詢的知識範圍。未提供或 null＝未設定（不限制）；空物件 {}＝視同不限制（全選），並非無權限；knowledgeBases 為空陣列或 null＝全部不可查（無權限）；labelRelations.conditions 為空陣列＝不做標籤過濾（並非無權限）。詳見本端點說明。 (非必填)
  {
    "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"?: [ // 自訂聯絡人屬性列表 (非必填)
    {
      "key": string // 屬性名稱
      "value": string // 屬性值
      "updatedAt"?: string // 更新時間（ISO 格式，可選，未提供則自動填入） (非必填)
    }
  ]
}
```

**請求範例值**

```json
{
  "inboxes": [
    {
      "id": "new_inbox_uuid"
    }
  ],
  "name": "updated_user_name",
  "avatar": "updated_avatar_url",
  "phoneNumber": 987654321,
  "email": "updated@example.com",
  "sourceId": "updated_source_id",
  "queryMetadata": {
    "knowledgeBases": []
  },
  "metadata": [
    {
      "key": "客戶等級",
      "value": "VVIP"
    },
    {
      "key": "偏好語言",
      "value": "日本語"
    }
  ]
}
```

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X PUT "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inboxes": [
      {
        "id": "new_inbox_uuid"
      }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
      "knowledgeBases": []
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VVIP"
      },
      {
        "key": "偏好語言",
        "value": "日本語"
      }
    ]
  }'

# 請確認在執行前替換 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 = {
    "inboxes": [
      {
        "id": "new_inbox_uuid"
      }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
      "knowledgeBases": []
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VVIP"
      },
      {
        "key": "偏好語言",
        "value": "日本語"
      }
    ]
  };

axios.put("https://api.maiagent.ai/api/v1/contacts/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/contacts/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "inboxes": [
        {
            "id": "new_inbox_uuid"
        }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
        "knowledgeBases": []
    },
    "metadata": [
        {
            "key": "客戶等級",
            "value": "VVIP"
        },
        {
            "key": "偏好語言",
            "value": "日本語"
        }
    ]
}

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/contacts/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'inboxes' => [
                [
                    'id' => 'new_inbox_uuid'
                ]
            ],
            'name' => 'updated_user_name',
            'avatar' => 'updated_avatar_url',
            'phoneNumber' => 987654321,
            'email' => 'updated@example.com',
            'sourceId' => 'updated_source_id',
            'queryMetadata' => [
                'knowledgeBases' => []
            ],
            'metadata' => [
                [
                    'key' => '客戶等級',
                    'value' => 'VVIP'
                ],
                [
                    'key' => '偏好語言',
                    'value' => '日本語'
                ]
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "user1_uuid",
  "inboxes": [
    {
      "id": "inbox_uuid",
      "name": "inbox_name"
    }
  ],
  "name": "user1",
  "avatar": "",
  "phoneNumber": 912345678,
  "email": "user1@example.com",
  "sourceId": null,
  "queryMetadata": null,
  "createdAt": "1751875361000",
  "updatedAt": "1751875361000"
}
```

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

***

### 部分更新聯絡人 <a href="#contacts-partial-update" id="contacts-partial-update"></a>

PATCH `/api/v1/contacts/{id}/`

#### 參數

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

#### 請求內容

**請求參數**

| 欄位                                      | 類型                     | 必填 | 說明                                                                                                                                                                    |
| --------------------------------------- | ---------------------- | -- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name                                    | string                 | 否  | 聯絡人姓名                                                                                                                                                                 |
| inboxes                                 | array\[object]         | 否  | 對話平台列表（新版格式）                                                                                                                                                          |
| inbox                                   | object                 | 否  | 單一對話平台（舊版格式，向前相容）                                                                                                                                                     |
| inbox.id                                | string (uuid)          | 是  | 對話平台 ID                                                                                                                                                               |
| avatar                                  | string                 | 否  | 頭像URL                                                                                                                                                                 |
| phoneNumber                             | string                 | 否  | 聯絡人電話號碼                                                                                                                                                               |
| email                                   | string (email)         | 否  | 聯絡人電子信箱                                                                                                                                                               |
| sourceId                                | string                 | 否  | 來源ID                                                                                                                                                                  |
| queryMetadata                           | object                 | 否  | 查詢元資料（Query Metadata），控制可查詢的知識範圍。未提供或 null＝未設定（不限制）；空物件 {}＝視同不限制（全選），並非無權限；knowledgeBases 為空陣列或 null＝全部不可查（無權限）；labelRelations.conditions 為空陣列＝不做標籤過濾（並非無權限）。詳見本端點說明。 |
| 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                                | array\[object]         | 否  | 自訂聯絡人屬性列表                                                                                                                                                             |

**請求結構範例**

```typescript
{
  "name"?: string // 聯絡人姓名 (非必填)
  "inboxes"?: [ // 對話平台列表（新版格式） (非必填)
    {
      "id": string (uuid) // 對話平台 ID
    }
  ]
  "inbox"?: { // 單一對話平台（舊版格式，向前相容） (非必填)
  {
    "id": string (uuid) // 對話平台 ID
  }
  }
  "avatar"?: string // 頭像URL (非必填)
  "phoneNumber"?: string // 聯絡人電話號碼 (非必填)
  "email"?: string (email) // 聯絡人電子信箱 (非必填)
  "sourceId"?: string // 來源ID (非必填)
  "queryMetadata"?: { // 查詢元資料（Query Metadata），控制可查詢的知識範圍。未提供或 null＝未設定（不限制）；空物件 {}＝視同不限制（全選），並非無權限；knowledgeBases 為空陣列或 null＝全部不可查（無權限）；labelRelations.conditions 為空陣列＝不做標籤過濾（並非無權限）。詳見本端點說明。 (非必填)
  {
    "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"?: [ // 自訂聯絡人屬性列表 (非必填)
    {
      "key": string // 屬性名稱
      "value": string // 屬性值
      "updatedAt"?: string // 更新時間（ISO 格式，可選，未提供則自動填入） (非必填)
    }
  ]
}
```

**請求範例值**

```json
{
  "inboxes": [
    {
      "id": "new_inbox_uuid"
    }
  ],
  "name": "updated_user_name",
  "avatar": "updated_avatar_url",
  "phoneNumber": 987654321,
  "email": "updated@example.com",
  "sourceId": "updated_source_id",
  "queryMetadata": {
    "knowledgeBases": []
  },
  "metadata": [
    {
      "key": "客戶等級",
      "value": "VVIP"
    },
    {
      "key": "偏好語言",
      "value": "日本語"
    }
  ]
}
```

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X PATCH "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inboxes": [
      {
        "id": "new_inbox_uuid"
      }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
      "knowledgeBases": []
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VVIP"
      },
      {
        "key": "偏好語言",
        "value": "日本語"
      }
    ]
  }'

# 請確認在執行前替換 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 = {
    "inboxes": [
      {
        "id": "new_inbox_uuid"
      }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
      "knowledgeBases": []
    },
    "metadata": [
      {
        "key": "客戶等級",
        "value": "VVIP"
      },
      {
        "key": "偏好語言",
        "value": "日本語"
      }
    ]
  };

axios.patch("https://api.maiagent.ai/api/v1/contacts/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/contacts/550e8400-e29b-41d4-a716-446655440000/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "inboxes": [
        {
            "id": "new_inbox_uuid"
        }
    ],
    "name": "updated_user_name",
    "avatar": "updated_avatar_url",
    "phoneNumber": 987654321,
    "email": "updated@example.com",
    "sourceId": "updated_source_id",
    "queryMetadata": {
        "knowledgeBases": []
    },
    "metadata": [
        {
            "key": "客戶等級",
            "value": "VVIP"
        },
        {
            "key": "偏好語言",
            "value": "日本語"
        }
    ]
}

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/contacts/550e8400-e29b-41d4-a716-446655440000/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'inboxes' => [
                [
                    'id' => 'new_inbox_uuid'
                ]
            ],
            'name' => 'updated_user_name',
            'avatar' => 'updated_avatar_url',
            'phoneNumber' => 987654321,
            'email' => 'updated@example.com',
            'sourceId' => 'updated_source_id',
            'queryMetadata' => [
                'knowledgeBases' => []
            ],
            'metadata' => [
                [
                    'key' => '客戶等級',
                    'value' => 'VVIP'
                ],
                [
                    'key' => '偏好語言',
                    'value' => '日本語'
                ]
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "user1_uuid",
  "inboxes": [
    {
      "id": "inbox_uuid",
      "name": "inbox_name"
    }
  ],
  "name": "user1",
  "avatar": "",
  "phoneNumber": 912345678,
  "email": "user1@example.com",
  "sourceId": null,
  "queryMetadata": null,
  "createdAt": "1751875361000",
  "updatedAt": "1751875361000"
}
```

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

***

### 刪除聯絡人 <a href="#contacts-destroy" id="contacts-destroy"></a>

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

#### 參數

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

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/contacts/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/contacts/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/contacts/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/contacts/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 |
| 400 | 聯絡人還有關聯的對話，無法刪除  |

***

### 取得聯絡人的對話列表 <a href="#contacts-conversations-list" id="contacts-conversations-list"></a>

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

#### 參數

| 參數名稱         | 必填 | 類型      | 說明                                                    |
| ------------ | -- | ------- | ----------------------------------------------------- |
| `id`         | ✅  | string  | A UUID string identifying this Contact.               |
| `channels`   | ❌  | array   | Multiple values may be separated by commas.           |
| `externalId` | ❌  | string  | 外部使用者 ID（完全相符）                                        |
| `inbox`      | ❌  | string  | 按單一 inbox ID 過濾（UUID 格式）                              |
| `inboxes`    | ❌  | string  | 按多個 inbox IDs 過濾（逗號分隔，如：uuid1,uuid2 或使用多個 inboxes 參數） |
| `keyword`    | ❌  | string  | 搜尋對話中的訊息內容（不區分大小寫）                                    |
| `page`       | ❌  | integer | A page number within the paginated result set.        |
| `pageSize`   | ❌  | integer | Number of results to return per page.                 |
| `query`      | ❌  | string  |                                                       |
| `tags`       | ❌  | array   | Multiple values may be separated by commas.           |

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/?channels=example&externalId=example&inbox=example&inboxes=example&keyword=example&page=1&pageSize=1&query=example&tags=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/?channels=example&externalId=example&inbox=example&inboxes=example&keyword=example&page=1&pageSize=1&query=example&tags=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/?channels=example&externalId=example&inbox=example&inboxes=example&keyword=example&page=1&pageSize=1&query=example&tags=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/?channels=example&externalId=example&inbox=example&inboxes=example&keyword=example&page=1&pageSize=1&query=example&tags=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)
      "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="#contacts-conversations-latest-retrieve" id="contacts-conversations-latest-retrieve"></a>

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

#### 參數

| 參數名稱      | 必填 | 類型     | 說明                                                    |
| --------- | -- | ------ | ----------------------------------------------------- |
| `id`      | ✅  | string | A UUID string identifying this Contact.               |
| `inbox`   | ❌  | string | 按單一 inbox ID 過濾（UUID 格式）                              |
| `inboxes` | ❌  | string | 按多個 inbox IDs 過濾（逗號分隔，如：uuid1,uuid2 或使用多個 inboxes 參數） |
| `keyword` | ❌  | string | 搜尋對話中的訊息內容（不區分大小寫）                                    |

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/latest/?inbox=example&inboxes=example&keyword=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/latest/?inbox=example&inboxes=example&keyword=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/latest/?inbox=example&inboxes=example&keyword=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/contacts/550e8400-e29b-41d4-a716-446655440000/conversations/latest/?inbox=example&inboxes=example&keyword=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)
  "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": "回應字串"
}
```

**狀態碼: 404 - No response body**

***

### 群發訊息 <a href="#contacts-broadcast-message-create" id="contacts-broadcast-message-create"></a>

POST `/api/v1/contacts/broadcast-message/`

#### 請求內容

**請求參數**

| 欄位                | 類型             | 必填 | 說明                                                |
| ----------------- | -------------- | -- | ------------------------------------------------- |
| contactIds        | array\[string] | 否  | \[正向指定模式] 要發送訊息的 contact ID 列表                    |
| inboxId           | string (uuid)  | 否  | \[反向排除/全部發送模式] Inbox ID，會發送給該 inbox 下的所有 contacts |
| excludeContactIds | array\[string] | 否  | \[反向排除模式] 要排除的 contact ID 列表，需配合 inbox\_id 使用     |
| message           | string         | 是  | 要發送的訊息內容                                          |

**請求結構範例**

```typescript
{
  "contactIds"?: [ // [正向指定模式] 要發送訊息的 contact ID 列表 (非必填)
    string (uuid)
  ]
  "inboxId"?: string (uuid) // [反向排除/全部發送模式] Inbox ID，會發送給該 inbox 下的所有 contacts (非必填)
  "excludeContactIds"?: [ // [反向排除模式] 要排除的 contact ID 列表，需配合 inbox_id 使用 (非必填)
    string (uuid)
  ]
  "message": string // 要發送的訊息內容
}
```

**請求範例值**

```json
{
  "contactIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "inboxId": "550e8400-e29b-41d4-a716-446655440000",
  "excludeContactIds": [
    "550e8400-e29b-41d4-a716-446655440000"
  ],
  "message": "這是一個範例訊息"
}
```

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/contacts/broadcast-message/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contactIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "inboxId": "550e8400-e29b-41d4-a716-446655440000",
    "excludeContactIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "message": "這是一個範例訊息"
  }'

# 請確認在執行前替換 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 = {
    "contactIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "inboxId": "550e8400-e29b-41d4-a716-446655440000",
    "excludeContactIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ],
    "message": "這是一個範例訊息"
  };

axios.post("https://api.maiagent.ai/api/v1/contacts/broadcast-message/", 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/contacts/broadcast-message/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "contactIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "inboxId": "550e8400-e29b-41d4-a716-446655440000",
    "excludeContactIds": [
        "550e8400-e29b-41d4-a716-446655440000"
    ],
    "message": "這是一個範例訊息"
}

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/contacts/broadcast-message/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'contactIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'inboxId' => '550e8400-e29b-41d4-a716-446655440000',
            'excludeContactIds' => [
                '550e8400-e29b-41d4-a716-446655440000'
            ],
            'message' => '這是一個範例訊息'
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "results"?: [ // 非必填
    {
      "contactId"?: string (uuid) // 非必填
      "conversationId"?: string (uuid) // 非必填
      "messageId"?: string (uuid) // 非必填
      "status"?: string // 非必填
    }
  ]
  "errors"?: [ // 非必填
    {
      "contactId"?: string (uuid) // 非必填
      "error"?: string // 非必填
    }
  ]
  "totalContacts"?: integer // 非必填
  "successCount"?: integer // 非必填
  "errorCount"?: integer // 非必填
}
```

**回應範例值**

```json
{
  "results": [
    {
      "contactId": "550e8400-e29b-41d4-a716-446655440000",
      "conversationId": "550e8400-e29b-41d4-a716-446655440000",
      "messageId": "550e8400-e29b-41d4-a716-446655440000",
      "status": "success"
    }
  ],
  "errors": [
    {
      "contactId": "550e8400-e29b-41d4-a716-446655440000",
      "error": "回應字串"
    }
  ],
  "totalContacts": 456,
  "successCount": 456,
  "errorCount": 456
}
```

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

***

### 為聯絡人建立 API 憑證 <a href="#contacts-api-credentials-create" id="contacts-api-credentials-create"></a>

POST `/api/v1/contacts/{id}/api-credentials/`

{% hint style="info" %}
讓 Agent 以該聯絡人的身分呼叫您的 API 工具。流程見技術手冊[聯絡人憑證同步](https://docs.maiagent.ai/tech/authorization-integration/contact-credentials-sync)。
{% endhint %}

#### 參數

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

#### 請求內容

**請求參數**

| 欄位      | 類型            | 必填 | 說明         |
| ------- | ------------- | -- | ---------- |
| tool    | string (uuid) | 是  | API 工具的 ID |
| headers | object        | 否  | 認證標頭字典     |

**請求結構範例**

```typescript
{
  "tool": string (uuid) // API 工具的 ID
  "headers"?: object // 認證標頭字典 (非必填)
}
```

**請求範例值**

```json
{
  "tool": "550e8400-e29b-41d4-a716-446655440000",
  "headers": {}
}
```

#### 程式碼範例

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

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

# 請確認在執行前替換 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 = {
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "headers": {}
  };

axios.post("https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "headers": {}
}

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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'tool' => '550e8400-e29b-41d4-a716-446655440000',
            'headers' => new \stdClass()
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

**狀態碼: 400 - No response body**

***

### 更新聯絡人的 API 憑證 <a href="#contacts-api-credentials-partial-update" id="contacts-api-credentials-partial-update"></a>

PATCH `/api/v1/contacts/{id}/api-credentials/{credentialId}/`

#### 參數

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

#### 請求內容

**請求參數**

| 欄位      | 類型     | 必填 | 說明     |
| ------- | ------ | -- | ------ |
| headers | object | 否  | 認證標頭字典 |

**請求結構範例**

```typescript
{
  "headers"?: object // 認證標頭字典 (非必填)
}
```

**請求範例值**

```json
{
  "headers": {}
}
```

#### 程式碼範例

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

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

# 請確認在執行前替換 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 = {
    "headers": {}
  };

axios.patch("https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

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

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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'headers' => 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)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

**狀態碼: 404 - No response body**

***

### 刪除聯絡人的 API 憑證 <a href="#contacts-api-credentials-destroy" id="contacts-api-credentials-destroy"></a>

DELETE `/api/v1/contacts/{id}/api-credentials/{credentialId}/`

#### 參數

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

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/" \
  -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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/"
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/contacts/550e8400-e29b-41d4-a716-446655440000/api-credentials/{credentialId}/", [
        '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 |
| 404 | No response body |

***

### 為聯絡人建立 MCP 憑證 <a href="#contacts-mcp-credentials-create" id="contacts-mcp-credentials-create"></a>

POST `/api/v1/contacts/{id}/mcp-credentials/`

#### 參數

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

#### 請求內容

**請求參數**

| 欄位      | 類型            | 必填 | 說明         |
| ------- | ------------- | -- | ---------- |
| tool    | string (uuid) | 是  | MCP 工具的 ID |
| headers | object        | 否  | 認證標頭字典     |

**請求結構範例**

```typescript
{
  "tool": string (uuid) // MCP 工具的 ID
  "headers"?: object // 認證標頭字典 (非必填)
}
```

**請求範例值**

```json
{
  "tool": "550e8400-e29b-41d4-a716-446655440000",
  "headers": {}
}
```

#### 程式碼範例

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

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

# 請確認在執行前替換 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 = {
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "headers": {}
  };

axios.post("https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

# 請求內容 (payload)
data = {
    "tool": "550e8400-e29b-41d4-a716-446655440000",
    "headers": {}
}

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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'tool' => '550e8400-e29b-41d4-a716-446655440000',
            'headers' => new \stdClass()
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 201**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

**狀態碼: 400 - No response body**

***

### 更新聯絡人的 MCP 憑證 <a href="#contacts-mcp-credentials-partial-update" id="contacts-mcp-credentials-partial-update"></a>

PATCH `/api/v1/contacts/{id}/mcp-credentials/{credentialId}/`

#### 參數

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

#### 請求內容

**請求參數**

| 欄位      | 類型     | 必填 | 說明     |
| ------- | ------ | -- | ------ |
| headers | object | 否  | 認證標頭字典 |

**請求結構範例**

```typescript
{
  "headers"?: object // 認證標頭字典 (非必填)
}
```

**請求範例值**

```json
{
  "headers": {}
}
```

#### 程式碼範例

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

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

# 請確認在執行前替換 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 = {
    "headers": {}
  };

axios.patch("https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY",
    "Content-Type": "application/json"
}

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

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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY',
            'Content-Type' => 'application/json'
        ],
        'json' => [
            'headers' => 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)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

**狀態碼: 404 - No response body**

***

### 刪除聯絡人的 MCP 憑證 <a href="#contacts-mcp-credentials-destroy" id="contacts-mcp-credentials-destroy"></a>

DELETE `/api/v1/contacts/{id}/mcp-credentials/{credentialId}/`

#### 參數

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

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X DELETE "https://api.maiagent.ai/api/v1/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/" \
  -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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/", 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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/"
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/contacts/550e8400-e29b-41d4-a716-446655440000/mcp-credentials/{credentialId}/", [
        '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 |
| 404 | No response body |

***

### 下載聯絡人批次匯入範本 <a href="#contacts-bulk-import-template-retrieve" id="contacts-bulk-import-template-retrieve"></a>

GET `/api/v1/contacts/bulk-import-template/`

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X GET "https://api.maiagent.ai/api/v1/contacts/bulk-import-template/" \
  -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/contacts/bulk-import-template/", 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/contacts/bulk-import-template/"
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/contacts/bulk-import-template/", [
        '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)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

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

***

### 批次匯入聯絡人 <a href="#contacts-bulk-import-create" id="contacts-bulk-import-create"></a>

POST `/api/v1/contacts/bulk-import/`

{% hint style="info" %}
上傳依範本填寫的 Excel；帶 `dry_run=true` 只回報將建立／更新的筆數而不寫入（回 `200` 而非 `201`）。
{% endhint %}

#### 程式碼範例

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

```bash
# 呼叫 API 示例 (Shell)
curl -X POST "https://api.maiagent.ai/api/v1/contacts/bulk-import/" \
  -H "Authorization: Api-Key YOUR_API_KEY"

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

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const axios = require('axios');
const FormData = require('form-data');

// 建立FormData對象
const formData = new FormData();
// 添加表單欄位

// 設定請求標頭
const config = {
  headers: {
    'Authorization': 'Api-Key YOUR_API_KEY',
    ...formData.getHeaders()
  }
};

axios.post("https://api.maiagent.ai/api/v1/contacts/bulk-import/", formData, 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/contacts/bulk-import/"
headers = {
    "Authorization": "Api-Key YOUR_API_KEY"
}

# 建立檔案和表單資料
files = {
    'file': ('example.pdf', open('example.pdf', 'rb'), 'application/pdf')
}

response = requests.post(url, files=files, 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/contacts/bulk-import/", [
        'headers' => [
            'Authorization' => 'Api-Key YOUR_API_KEY'
        ],
        'multipart' => [
            [
                'name' => 'file',
                'contents' => fopen('example.pdf', 'r'),
                'filename' => 'example.pdf'
            ]
        ]
    ]);
    
    $data = json_decode($response->getBody(), true);
    echo "成功取得回應:\n";
    print_r($data);
} catch (Exception $e) {
    echo '請求發生錯誤: ' . $e->getMessage();
}
?>
```

{% endtab %}
{% endtabs %}

#### 回應內容

**狀態碼: 200**

**回應結構範例**

```typescript
{
  "id": string (uuid)
  "inboxes"?: [ // 非必填
    {
      "id": string (uuid)
      "name": string
    }
  ]
  "inbox"?:  // 向前相容欄位：單一 inbox，若同時提供 inboxes 則忽略此欄位 (非必填)
  {
    "id": string (uuid)
    "name": string
  }
  "name": string
  "avatar"?: // 可能有不同的類型 (非必填)
  string (uri) // 聯絡人頭像 URL，支援完整 URL 或相對路徑 (非必填)
  "phoneNumber"?: string // 非必填
  "email"?: // 可能有不同的類型 (非必填)
  string (email) // 非必填
  "sourceId"?: string // 非必填
  "externalId"?: string // 外部使用者 ID：呼叫端系統自己的使用者 ID，同一組織內唯一（已刪除的聯絡人不計），原字串完全比對、區分大小寫；對話 API 的 message.externalUser.id 以此找到聯絡人。空字串或全空白回 400，要清除請帶 null。多個外部系統建議加系統前綴，例如 projects:usr_123 (非必填)
  "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 // Custom customer information shown in the customer panel of the conversation page (非必填)
  "mcpCredentials": [ // 聯絡人的 MCP 認證憑證列表
    object
  ]
  "apiCredentials": [ // 聯絡人的 API 認證憑證列表
    object
  ]
  "contactConnectors": [ // 聯絡人的 Connector OAuth 授權列表（不含 token 本體）
    object
  ]
  "tags": [
    {
      "id": string (uuid)
      "name": string
      "createdAt": string (timestamp)
      "updatedAt": string (timestamp)
    }
  ]
  "preChatFieldIndex": object // 來自此 Contact 所屬 inboxes 的 pre-chat form 欄位設定，mapping {field_id: {label: {locale: text}}}，前端用來把 metadata 的 UUID key 解析成顯示名稱
  "createdAt": string (timestamp)
  "updatedAt": string (timestamp)
}
```

**回應範例值**

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "inboxes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串"
    }
  ],
  "inbox": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應字串"
  },
  "name": "回應字串",
  "avatar": "https://example.com/file.jpg",
  "phoneNumber": "回應字串",
  "email": "response@example.com",
  "sourceId": "回應字串",
  "externalId": "回應字串",
  "queryMetadata": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "metadata": null,
  "mcpCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "apiCredentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "contactConnectors": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應範例名稱",
      "description": "回應範例描述"
    }
  ],
  "tags": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "回應字串",
      "createdAt": "回應字串",
      "updatedAt": "回應字串"
    }
  ],
  "preChatFieldIndex": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "回應範例名稱",
    "description": "回應範例描述"
  },
  "createdAt": "回應字串",
  "updatedAt": "回應字串"
}
```

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

***


---

# 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/lian-luo-ren.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.
