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

# 竞争对手

> 管理竞争对手品牌并获取其聚合指标。

竞争对手是 Topify.ai 在 AI 回复中与您一同跟踪的品牌。此端点返回活跃的竞争对手，并附带聚合的可见度、情感分析和位置指标。

## 列出竞争对手

```
GET /projects/{project_id}/competitors
```

返回项目中所有活跃的竞争对手，及给定日期范围内的聚合指标。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |

### 查询参数

| 参数              | 类型      | 默认值 | 描述                 |
| --------------- | ------- | --- | ------------------ |
| `duration_days` | integer | `7` | 回溯天数               |
| `date_from`     | string  | --  | 起始日期（`YYYY-MM-DD`） |
| `date_to`       | string  | --  | 结束日期（`YYYY-MM-DD`） |
| `providers`     | string  | --  | 以逗号分隔的 AI 服务商筛选    |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors?duration_days=7" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.get(f"/projects/{project_id}/competitors", params={"duration_days": 7})
    ```
  </Tab>

  <Tab title="Node.js（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors?duration_days=7`, { headers });
    ```
  </Tab>
</Tabs>

### 响应

```json theme={null}
{
  "success": true,
  "data": {
    "active_competitors": [
      {
        "competitor_id": "00000000-0000-0000-0000-000000000000",
        "project_id": "a1b2c3d4-...",
        "name": "Acme Corp",
        "website": "https://acme.com",
        "icon_url": "https://logo.clearbit.com/acme.com",
        "icon_urls": [
          "https://logo.clearbit.com/acme.com",
          "https://www.google.com/s2/favicons?domain=acme.com&sz=64"
        ],
        "state": "active",
        "is_own_brand": true,
        "metrics": {
          "visibility": 85.0,
          "sentiment": 72.0,
          "position": 1.8,
          "mention_count": null,
          "days_with_data": 7,
          "period": "2026-02-27 to 2026-03-06"
        }
      },
      {
        "competitor_id": "c1d2e3f4-...",
        "project_id": "a1b2c3d4-...",
        "name": "Competitor A",
        "website": "https://competitor-a.com",
        "icon_url": "https://logo.clearbit.com/competitor-a.com",
        "icon_urls": [
          "https://logo.clearbit.com/competitor-a.com",
          "https://www.google.com/s2/favicons?domain=competitor-a.com&sz=64"
        ],
        "state": "active",
        "is_own_brand": false,
        "metrics": {
          "visibility": 72.0,
          "sentiment": 65.0,
          "position": 3.1,
          "mention_count": null,
          "days_with_data": 7,
          "period": "2026-02-27 to 2026-03-06"
        }
      }
    ],
    "total_active": 8
  }
}
```

### CompetitorResponse 字段

| 字段              | 类型                | 可空  | 描述                                        |
| --------------- | ----------------- | --- | ----------------------------------------- |
| `competitor_id` | string (UUID)     | No  | 竞争对手 ID。`00000000-...` 表示注入的自有品牌          |
| `project_id`    | string (UUID)     | No  | 父项目 ID                                    |
| `name`          | string            | No  | 竞争对手品牌名称                                  |
| `website`       | string            | No  | 竞争对手网站 URL                                |
| `icon_url`      | string            | Yes | 主要 logo URL                               |
| `icon_urls`     | string\[]         | No  | 多个 logo URL 来源（Clearbit + Google favicon） |
| `state`         | string            | Yes | 在此端点中始终为 `active`                         |
| `is_own_brand`  | boolean           | No  | 如果这是您自己的品牌则为 `true`                       |
| `metrics`       | CompetitorMetrics | Yes | 日期范围内的聚合指标                                |

### CompetitorMetrics 字段

| 字段               | 类型      | 可空  | 描述                                       |
| ---------------- | ------- | --- | ---------------------------------------- |
| `visibility`     | float   | Yes | 该周期内的平均可见度评分                             |
| `sentiment`      | float   | Yes | 该周期内的平均情感分析评分                            |
| `position`       | float   | Yes | AI 回复中的平均位置                              |
| `mention_count`  | integer | Yes | 总提及次数（可能为 `null`）                        |
| `days_with_data` | integer | Yes | 收集到数据的天数                                 |
| `period`         | string  | No  | 人类可读的日期范围（例如 `2026-02-27 to 2026-03-06`） |

<Note>
  您自己的品牌始终包含在响应中，并以 `is_own_brand: true` 标识。如果您的品牌还未作为竞争对手存在，则会以零值指标自动注入，以便您直接进行比较。
</Note>

***

## 列出待审核竞争对手

```
GET /projects/{project_id}/competitors/pending
```

返回由 AI 发现、等待跟踪或拒绝决定的竞争对手。待审核竞争对手尚无分析指标。

```bash theme={null}
curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors/pending" \
  -H "X-API-Key: tk_live_..."
```

```json theme={null}
{
  "success": true,
  "data": {
    "pending_competitors": [
      {
        "competitor_id": "e5f6a7b8-...",
        "project_id": "a1b2c3d4-...",
        "name": "Acme",
        "website": "https://acme.com",
        "state": "pending",
        "is_own_brand": false,
        "metrics": null
      }
    ],
    "total_pending": 1
  }
}
```

## 审核待定竞争对手

```
PATCH /projects/{project_id}/competitors/{competitor_id}/state
```

跟踪或拒绝待审核竞争对手。发送 `active` 开始跟踪，或发送 `inactive` 拒绝。只有当前处于 `pending` 状态的竞争对手可通过此端点审核。

```bash theme={null}
curl -X PATCH "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors/{competitor_id}/state" \
  -H "X-API-Key: tk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"state":"active"}'
```

| 字段      | 类型     | 必填 | 描述                            |
| ------- | ------ | -- | ----------------------------- |
| `state` | string | 是  | `active` 表示跟踪，`inactive` 表示拒绝 |

| 状态    | 原因            |
| ----- | ------------- |
| `400` | 目标状态无效        |
| `404` | 在此项目中未找到竞争对手  |
| `409` | 竞争对手当前不是待审核状态 |

***

## 创建竞争对手

```
POST /projects/{project_id}/competitors
```

向项目中添加一个或多个竞争对手品牌。每个竞争对手会立即开始跟踪。

<Warning>
  API 密钥由管理员创建，目前对整个团队拥有完整权限。创建竞争对手前请确认项目和列表。
</Warning>

### 路径参数

| 参数           | 类型            | 描述         |
| ------------ | ------------- | ---------- |
| `project_id` | string (UUID) | 要添加竞争对手的项目 |

### 请求体

| 字段                      | 类型        | 必填  | 描述                                            |
| ----------------------- | --------- | --- | --------------------------------------------- |
| `competitors`           | object\[] | Yes | 要添加的竞争对手数组（每次请求 1--20 个）                      |
| `competitors[].name`    | string    | Yes | 品牌名称                                          |
| `competitors[].website` | string    | Yes | 网站域名或 URL（例如 `acme.com` 或 `https://acme.com`） |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{
        "competitors": [
          {"name": "Acme Corp", "website": "acme.com"},
          {"name": "Globex Inc", "website": "globex.net"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/competitors", json={
        "competitors": [
            {"name": "Acme Corp", "website": "acme.com"},
            {"name": "Globex Inc", "website": "globex.net"},
        ],
    })
    ```
  </Tab>

  <Tab title="Node.js（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({
        competitors: [
          { name: "Acme Corp", website: "acme.com" },
          { name: "Globex Inc", website: "globex.net" },
        ],
      }),
    });
    ```
  </Tab>
</Tabs>

### 响应

```json theme={null}
{
  "code": 200,
  "message": "200 OK",
  "data": {
    "projectId": "a1b2c3d4-...",
    "created": 2,
    "competitors": [
      {
        "competitorId": "c1d2e3f4-...",
        "projectId": "a1b2c3d4-...",
        "name": "Acme Corp",
        "website": "https://acme.com",
        "iconUrl": "https://img.logo.dev/acme.com?token=...",
        "iconUrls": ["https://img.logo.dev/acme.com?token=..."],
        "state": "active",
        "isOwnBrand": false,
        "metrics": null
      }
    ]
  }
}
```

### 错误响应

| 状态    | 原因                                 |
| ----- | ---------------------------------- |
| `400` | 竞争对手数组为空、名称为空、网站 URL 无效，或请求中存在重复域名 |
| `409` | 项目中已存在相同域名的竞争对手                    |
| `429` | 已达到活跃竞争对手数量上限（最多 10 个）             |

***

## 更新竞争对手

```
PATCH /projects/{project_id}/competitors/{competitor_id}
```

更新现有竞争对手的名称或网站。

<Warning>
  API 密钥由管理员创建，目前对整个团队拥有完整权限。更新竞争对手前请确认项目和字段。
</Warning>

### 路径参数

| 参数              | 类型            | 描述       |
| --------------- | ------------- | -------- |
| `project_id`    | string (UUID) | 项目 ID    |
| `competitor_id` | string (UUID) | 要更新的竞争对手 |

### 请求体

所有字段均为可选。仅包含您想要修改的字段。

| 字段        | 类型     | 描述           |
| --------- | ------ | ------------ |
| `name`    | string | 新的品牌名称（不能为空） |
| `website` | string | 新的网站域名或 URL  |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X PATCH "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors/{competitor_id}" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{"name": "Acme Inc", "website": "acmeinc.com"}'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.patch(f"/projects/{project_id}/competitors/{competitor_id}", json={
        "name": "Acme Inc",
    })
    ```
  </Tab>

  <Tab title="Node.js（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors/${competitorId}`, {
      method: "PATCH",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({ name: "Acme Inc" }),
    });
    ```
  </Tab>
</Tabs>

### 响应

返回更新后的竞争对手及其全部字段（与 [列出竞争对手](#list-competitors) 中的项形状相同）。

### 错误响应

| 状态    | 原因                                |
| ----- | --------------------------------- |
| `400` | 请求体为空、名称只有空白字符、网站 URL 无效，或没有字段被修改 |
| `403` | API 密钥具有只读权限                      |
| `404` | 在此项目中未找到竞争对手                      |

***

## 删除竞争对手

```
DELETE /projects/{project_id}/competitors/{competitor_id}
```

从您的项目中永久删除一个竞争对手并停止跟踪。

<Warning>
  此操作不可撤销。API 密钥由管理员创建，目前对整个团队拥有完整权限。
</Warning>

### 路径参数

| 参数              | 类型            | 描述       |
| --------------- | ------------- | -------- |
| `project_id`    | string (UUID) | 项目 ID    |
| `competitor_id` | string (UUID) | 要删除的竞争对手 |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X DELETE "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/competitors/{competitor_id}" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.delete(f"/projects/{project_id}/competitors/{competitor_id}")
    ```
  </Tab>

  <Tab title="Node.js（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors/${competitorId}`, {
      method: "DELETE",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应

```json theme={null}
{
  "code": 200,
  "message": "200 OK",
  "data": {
    "competitorId": "c1d2e3f4-...",
    "message": "Competitor deleted successfully"
  }
}
```

### 错误响应

| 状态    | 原因           |
| ----- | ------------ |
| `403` | API 密钥具有只读权限 |
| `404` | 在此项目中未找到竞争对手 |
