> ## 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.

# Competitors

> Manage competitor brands and retrieve their aggregated metrics.

Competitors are the brands Topify.ai tracks alongside yours across AI responses. This endpoint returns active competitors with aggregated visibility, sentiment, and position metrics.

## List competitors

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

Returns all active competitors for a project with aggregated metrics for the given date range.

### Path parameters

| Param        | Type          | Description    |
| ------------ | ------------- | -------------- |
| `project_id` | string (UUID) | The project ID |

### Query parameters

| Param           | Type    | Default | Description                     |
| --------------- | ------- | ------- | ------------------------------- |
| `duration_days` | integer | `7`     | Days to look back               |
| `date_from`     | string  | --      | Start date (`YYYY-MM-DD`)       |
| `date_to`       | string  | --      | End date (`YYYY-MM-DD`)         |
| `providers`     | string  | --      | Comma-separated provider filter |

<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="JavaScript">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors?duration_days=7`, { headers });
    ```
  </Tab>
</Tabs>

### Response

```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 fields

| Field           | Type              | Nullable | Description                                           |
| --------------- | ----------------- | -------- | ----------------------------------------------------- |
| `competitor_id` | string (UUID)     | No       | Competitor ID. `00000000-...` for injected own brand  |
| `project_id`    | string (UUID)     | No       | Parent project ID                                     |
| `name`          | string            | No       | Competitor brand name                                 |
| `website`       | string            | No       | Competitor website URL                                |
| `icon_url`      | string            | Yes      | Primary logo URL                                      |
| `icon_urls`     | string\[]         | No       | Multiple logo URL sources (Clearbit + Google favicon) |
| `state`         | string            | Yes      | Always `active` in this endpoint                      |
| `is_own_brand`  | boolean           | No       | `true` if this is your own brand                      |
| `metrics`       | CompetitorMetrics | Yes      | Aggregated metrics for the date range                 |

### CompetitorMetrics fields

| Field            | Type    | Nullable | Description                                                  |
| ---------------- | ------- | -------- | ------------------------------------------------------------ |
| `visibility`     | float   | Yes      | Average visibility score across the period                   |
| `sentiment`      | float   | Yes      | Average sentiment score across the period                    |
| `position`       | float   | Yes      | Average position in AI responses                             |
| `mention_count`  | integer | Yes      | Total mention count (may be `null`)                          |
| `days_with_data` | integer | Yes      | Number of days with collected data                           |
| `period`         | string  | No       | Human-readable date range (e.g., `2026-02-27 to 2026-03-06`) |

<Note>
  Your own brand is always included in the response with `is_own_brand: true`. If your brand doesn't already exist as a competitor, it is injected automatically with zeroed metrics so you can compare directly.
</Note>

***

## Create competitors

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

Add one or more competitor brands to a project. Each competitor begins tracking immediately.

<Warning>
  Requires an admin-scoped API key. Viewer keys receive a `403` response.
</Warning>

### Path parameters

| Param        | Type          | Description                       |
| ------------ | ------------- | --------------------------------- |
| `project_id` | string (UUID) | The project to add competitors to |

### Request body

| Field                   | Type      | Required | Description                                                   |
| ----------------------- | --------- | -------- | ------------------------------------------------------------- |
| `competitors`           | object\[] | Yes      | Array of competitors to add (1--20 per request)               |
| `competitors[].name`    | string    | Yes      | Brand name                                                    |
| `competitors[].website` | string    | Yes      | Website domain or URL (e.g. `acme.com` or `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="JavaScript">
    ```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>

### Response

```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
      }
    ]
  }
}
```

### Error responses

| Status | Cause                                                                                    |
| ------ | ---------------------------------------------------------------------------------------- |
| `400`  | Empty competitors array, empty name, invalid website URL, or duplicate domain in request |
| `403`  | API key has read-only (viewer) access                                                    |
| `409`  | A competitor with the same domain already exists in this project                         |
| `429`  | Active competitor limit reached (max 10)                                                 |

***

## Update competitor

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

Update the name or website of an existing competitor.

<Warning>
  Requires an admin-scoped API key.
</Warning>

### Path parameters

| Param           | Type          | Description              |
| --------------- | ------------- | ------------------------ |
| `project_id`    | string (UUID) | The project ID           |
| `competitor_id` | string (UUID) | The competitor to update |

### Request body

All fields are optional. Include only the fields you want to change.

| Field     | Type   | Description                      |
| --------- | ------ | -------------------------------- |
| `name`    | string | New brand name (cannot be empty) |
| `website` | string | New website domain or 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="JavaScript">
    ```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>

### Response

Returns the updated competitor with all fields (same shape as items in [list competitors](#list-competitors)).

### Error responses

| Status | Cause                                                                               |
| ------ | ----------------------------------------------------------------------------------- |
| `400`  | Empty request body, whitespace-only name, invalid website URL, or no fields changed |
| `403`  | API key has read-only access                                                        |
| `404`  | Competitor not found in this project                                                |

***

## Delete competitor

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

Permanently remove a competitor from your project and stop tracking it.

<Warning>
  This action cannot be undone. Requires an admin-scoped API key.
</Warning>

### Path parameters

| Param           | Type          | Description              |
| --------------- | ------------- | ------------------------ |
| `project_id`    | string (UUID) | The project ID           |
| `competitor_id` | string (UUID) | The competitor to delete |

<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="JavaScript">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/competitors/${competitorId}`, {
      method: "DELETE",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response

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

### Error responses

| Status | Cause                                |
| ------ | ------------------------------------ |
| `403`  | API key has read-only access         |
| `404`  | Competitor not found in this project |
