---
title: "Add competitors"
method: POST
path: "/api/mcp/projects/{projectId}/competitors"
tags: ["Competitors"]
---

# Add competitors

`POST /api/mcp/projects/{projectId}/competitors`

## Request

- Base URL: `https://app.searchable.com`
- URL: `https://app.searchable.com/api/mcp/projects/{projectId}/competitors`
- Auth: HTTP bearer

Add 1-20 competitors (each by website domain, optionally named) to the project's real/tracked competitor set. An entry that does not resolve to a website domain, such as a bare company name, is refused with 400 `invalid_argument`. `source: "manual"` with exactly one item also runs the duplicate check (409 conflict) the in-app add-competitor dialog runs. Requires the `competitor:match` capability. A pitch project that is not currently active refuses with 409 `INACTIVE_PITCH_PROMPT_MUTATION`.

## Path parameters

- `projectId` string, uuid, required

## Request body

- AddCompetitorsRequest
  - `competitors` AddCompetitorItem[], required
    - union
      - string: A website domain or URL, e.g. example.com.
      - object
        - `domain` string
        - `name` string
  - `source` 'manual' | 'ai_discovery': "manual" with exactly one item also runs the duplicate check (409 conflict) the in-app add-competitor dialog runs.

## Response `200`

Competitors added.

- AddCompetitorsResponse
  - `success` boolean, required
  - `added` integer, required
  - `updated` integer, required
  - `newDomains` string[]: The domains added as new competitors.
  - `alreadyTracked` string[]: The domains that matched a competitor already tracked, by domain or name, so were not added again.
  - `competitors` CompetitorRecord[], required
    - `id` string, uuid, required
    - `name` string, nullable
    - `domain` string, nullable
    - `addedBy` 'user' | 'ai_discovery', nullable
    - `domainSetBy` string, nullable
    - `isDirectCompetitor` boolean, nullable
    - `createdAt` string, date-time
    - `updatedAt` string, date-time

## Other responses

- `400`: Error response. `code` is the machine-readable reason — see the [error reference](/api/errors) for the full catalog and remediation per code.
- `401`: Error response. `code` is the machine-readable reason — see the [error reference](/api/errors) for the full catalog and remediation per code.
- `403`: Error response. `code` is the machine-readable reason — see the [error reference](/api/errors) for the full catalog and remediation per code.
- `404`: Error response. `code` is the machine-readable reason — see the [error reference](/api/errors) for the full catalog and remediation per code.
- `409`: Error response. `code` is the machine-readable reason — see the [error reference](/api/errors) for the full catalog and remediation per code.
- `429`: Rate limited. Usually the per-API-key REST limit (600 requests/minute); on Google-backed endpoints it can also relay an upstream Google rate limit. `Retry-After` (seconds) is present when the limit was applied by Searchable's own rate limiter; it may be absent when an upstream provider rate-limits.

## Changes

- **2026-11-03** `28a5e2a65cd3`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/searchable/apis/searchable-rest-api/changes/api/mcp/projects/:projectId/competitors/post.md)

---

[API](https://skmtc.dev/searchable/apis/searchable-rest-api.md) - [All operations](https://skmtc.dev/searchable/apis/searchable-rest-api/llms.txt) - [OpenAPI document](https://skmtc.dev/searchable/apis/searchable-rest-api/revisions/a1cc70e46e73?raw)
