> ## 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="Node.js (server-side)">
    ```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>

***

## List pending competitors

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

Returns AI-discovered competitors that are waiting for a track or reject decision. Pending competitors do not have analytics metrics yet.

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

## Review a pending competitor

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

Track or reject a pending competitor. Send `active` to begin tracking it, or `inactive` to reject it. Only competitors currently in `pending` state can be reviewed through this endpoint.

```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"}'
```

| Field   | Type   | Required | Description                               |
| ------- | ------ | -------- | ----------------------------------------- |
| `state` | string | Yes      | `active` to track or `inactive` to reject |

| Status | Cause                                |
| ------ | ------------------------------------ |
| `400`  | Invalid target state                 |
| `404`  | Competitor not found in this project |
| `409`  | Competitor is not currently pending  |

***

## Create competitors

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

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

<Warning>
  API keys are admin-created and currently have full-team access. Confirm the project and competitor list before creating competitors.
</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="Node.js (server-side)">
    ```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 |
| `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>
  API keys are admin-created and currently have full-team access. Confirm the project and fields before updating a competitor.
</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="Node.js (server-side)">
    ```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 |
| `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. API keys are admin-created and currently have full-team access.
</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="Node.js (server-side)">
    ```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                                |
| ------ | ------------------------------------ |
| `404`  | Competitor not found in this project |
