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

# Edit a competitor

> Edit a tracked competitor as the in-app competitor sheet does: rename it, change its website domain, make it a direct or a SERP competitor, and add or remove the other names it goes by (name variations), which is how its mentions are recognised in AI answers. Changing the domain, or making it direct, re-matches its past mentions in the background. Everything is checked before anything is written: a variation that is another competitor's name is refused with 409 `conflict` (merge the two in the app instead), and removing a name the competitor does not have is refused with 400. A name confirmed as another competitor's variation moves to this one. A body with no fields changes nothing and answers with the competitor and its name variations. Requires the `competitor:match` capability and a manage-tier role, as in the app. A pitch project that is not currently active refuses with 409 `INACTIVE_PITCH_PROMPT_MUTATION`.



## OpenAPI

````yaml /api-reference/openapi.json patch /api/mcp/projects/{projectId}/competitors/{competitorId}
openapi: 3.1.0
info:
  title: Searchable REST API
  version: 1.0.0
  summary: >-
    Query AI visibility, sources, sentiment, traffic, and content data, and
    trigger audits/reports/sitemap syncs.
  description: >-
    The Searchable REST API (`/api/mcp/*` and
    `/api/v1/projects/{projectId}/audits`) exposes the same data and actions
    available in the Searchable dashboard and MCP server, over plain HTTP with a
    bearer API key. It is a **read-mostly** surface — 75 of its 91 operations
    are GET. The mutating ones are capability-gated (a bare `write` scope does
    not satisfy a capability such as `prompt:draft`), and those listed under
    [Idempotency](/api-reference/introduction#idempotency) support
    `Idempotency-Key` replay.


    See **[Getting started](/api-reference/introduction)** for auth, rate
    limits, idempotency, and pagination conventions, and the **[error
    reference](/api/errors)** for every error `code` this API returns.


    `/api/mcp/*` is a frozen v1 contract — see the [changelog](/changelog) for
    the deprecation policy.
  contact:
    name: Searchable Support
    email: support@searchable.com
    url: https://docs.searchable.com/api-reference/introduction
servers:
  - url: https://app.searchable.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Projects
    description: List and inspect the projects an API key can reach.
  - name: Visibility
    description: >-
      AI visibility score, platform/topic/prompt/location breakdowns, and
      historical trend.
  - name: Share of Voice
    description: Brand vs. competitor mention-share ranking and its daily trend.
  - name: Competitors
    description: >-
      The project's tracked competitor roster — share of voice, sentiment, and
      mention/citation counts.
  - name: Sources
    description: >-
      Domains and URLs cited by AI answers — citation share, trend, and cached
      page content.
  - name: Sentiment
    description: Brand sentiment summary, trend, and head-to-head competitor comparison.
  - name: Query Fanout
    description: The sub-queries AI models generate when answering tracked prompts.
  - name: Traffic
    description: >-
      First-party AI-crawler and AI-referral traffic sourced from the
      tracker/CDN pipeline.
  - name: Shopping
    description: AI shopping/product-carousel visibility.
  - name: Ads
    description: >-
      Sponsored ads surfaced in AI answers — advertisers, individual creatives,
      ad-heavy prompts, and the frequency trend.
  - name: Answers
    description: Raw, per-response AI-answer data for a single prompt.
  - name: GSC
    description: Live Google Search Console performance data for the project's linked site.
  - name: GA4
    description: Live Google Analytics 4 traffic and AI-referral data.
  - name: Audits & Issues
    description: >-
      Page audits (technical + AEO), site issues, monitored pages, and sitemap
      sync.
  - name: Reports
    description: Generate and list shareable visibility/sentiment reports.
  - name: Articles
    description: Content pieces (articles) created in Searchable.
  - name: Opportunities
    description: >-
      Actionable, prioritized suggestions Searchable has surfaced for the
      project.
  - name: Brand
    description: Brand profile (knowledge base + AI-observed facts) and domain authority.
  - name: Prompts
    description: >-
      The project's prompt catalog (tracked, untracked, and AI-suggested
      prompts).
paths:
  /api/mcp/projects/{projectId}/competitors/{competitorId}:
    patch:
      tags:
        - Competitors
      summary: Edit a competitor
      description: >-
        Edit a tracked competitor as the in-app competitor sheet does: rename
        it, change its website domain, make it a direct or a SERP competitor,
        and add or remove the other names it goes by (name variations), which is
        how its mentions are recognised in AI answers. Changing the domain, or
        making it direct, re-matches its past mentions in the background.
        Everything is checked before anything is written: a variation that is
        another competitor's name is refused with 409 `conflict` (merge the two
        in the app instead), and removing a name the competitor does not have is
        refused with 400. A name confirmed as another competitor's variation
        moves to this one. A body with no fields changes nothing and answers
        with the competitor and its name variations. Requires the
        `competitor:match` capability and a manage-tier role, as in the app. A
        pitch project that is not currently active refuses with 409
        `INACTIVE_PITCH_PROMPT_MUTATION`.
      operationId: updateCompetitor
      parameters:
        - $ref: '#/components/parameters/projectId'
        - $ref: '#/components/parameters/competitorId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCompetitorRequest'
      responses:
        '200':
          description: Competitor updated.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/XRequestId'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
            X-RateLimit-Limit:
              $ref: '#/components/headers/XRateLimitLimit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/XRateLimitReset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateCompetitorResponse'
        '400':
          $ref: '#/components/responses/defaultError'
        '401':
          $ref: '#/components/responses/defaultError'
        '403':
          $ref: '#/components/responses/defaultError'
        '404':
          $ref: '#/components/responses/defaultError'
        '409':
          $ref: '#/components/responses/defaultError'
        '429':
          $ref: '#/components/responses/rateLimited'
components:
  parameters:
    projectId:
      name: projectId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: The project id.
    competitorId:
      name: competitorId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: The competitor's id.
  schemas:
    UpdateCompetitorRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
          description: The competitor's new name.
        domain:
          type: string
          minLength: 1
          maxLength: 253
          description: Its website domain, e.g. example.com.
        isDirectCompetitor:
          type: boolean
          description: >-
            true makes it a direct competitor, explicitly tracked; false makes
            it a SERP competitor, one that appears when AI results mention it.
        addVariations:
          type: array
          maxItems: 20
          items:
            type: string
            minLength: 1
            maxLength: 200
          description: Other names it goes by, to add.
        removeVariations:
          type: array
          maxItems: 20
          items:
            type: string
            minLength: 1
            maxLength: 200
          description: Name variations to remove. Each must be one it has.
    UpdateCompetitorResponse:
      type: object
      properties:
        success:
          type: boolean
        competitor:
          type: object
          properties:
            id:
              type: string
              format: uuid
            name:
              type:
                - string
                - 'null'
            domain:
              type:
                - string
                - 'null'
            isDirectCompetitor:
              type: boolean
          required:
            - id
            - name
            - domain
            - isDirectCompetitor
        variations:
          type: array
          items:
            type: string
          description: Its name variations after the edit.
        added:
          type: array
          description: >-
            The variations added. movedFrom names the competitor a confirmed
            variation moved off.
          items:
            type: object
            properties:
              name:
                type: string
              movedFrom:
                anyOf:
                  - type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type:
                          - string
                          - 'null'
                    required:
                      - id
                      - name
                  - type: 'null'
            required:
              - name
              - movedFrom
        removed:
          type: array
          items:
            type: string
          description: The variations removed.
      required:
        - success
        - competitor
        - variations
        - added
        - removed
    Problem:
      type: object
      description: >-
        RFC 9457 `application/problem+json` error body. `error` is retained
        verbatim as a legacy compat key equal to `message`. Some codes carry
        additional fields beyond the base shape (documented per-code in the
        [error reference](/api/errors)) — always additive, never replacing
        these.
      properties:
        type:
          type: string
          format: uri
          description: >-
            A URL identifying the error kind — the error reference page,
            anchored to `code`.
        title:
          type: string
          description: Human-readable summary of `code`.
        status:
          type: integer
          description: The HTTP status code (matches the response status).
        code:
          type: string
          description: >-
            Machine-readable, stable error code — safe to branch on. See the
            [error reference](/api/errors) for the full catalog.
          enum:
            - unauthorized
            - forbidden
            - missing_scope
            - plan_upgrade_required
            - not_found
            - invalid_argument
            - invalid_country
            - no_domain
            - no_workspace
            - no_pages
            - bulk_limit_exceeded
            - quota_exceeded
            - project_not_runnable
            - pitch_not_supported
            - rate_limited
            - idempotency_in_flight
            - query_timeout
            - gsc_not_connected
            - gsc_site_not_linked
            - gsc_access_denied
            - ga4_not_connected
            - traffic_not_connected
            - internal_error
        error:
          type: string
          description: Legacy compat key. Always equal to `message`.
        message:
          type: string
          description: Human-readable error message (identical to `error`).
        howToFix:
          type: string
          description: Present on actionable errors — a concrete next step.
        requestId:
          type: string
          format: uuid
          description: This request's id. Include it when contacting support.
        requiresUpgrade:
          type: boolean
          description: Present on `plan_upgrade_required` (403).
        retryable:
          type: boolean
          description: >-
            Present on `rate_limited`, `idempotency_in_flight`, and
            `query_timeout`.
        timeout:
          type: boolean
          description: Present on `query_timeout` (504).
        quotaExceeded:
          type: boolean
          description: Present on `quota_exceeded` (403).
        current:
          type: integer
          description: Present on `quota_exceeded` — current usage.
        limit:
          type: integer
          description: Present on `quota_exceeded` — the plan's limit.
        bulkLimitExceeded:
          type: boolean
          description: Present on `bulk_limit_exceeded` (400, `POST /audits`).
        requested:
          type: integer
          description: >-
            Present on `bulk_limit_exceeded` / `quota_exceeded` — the count
            requested.
        maxAllowed:
          type: integer
          description: Present on `bulk_limit_exceeded` — the plan's per-request cap.
        details:
          description: >-
            Present on some `invalid_argument` (400) responses — a Zod
            `.flatten()` validation breakdown.
          type: object
          properties:
            formErrors:
              type: array
              items:
                type: string
            fieldErrors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: string
      required:
        - type
        - title
        - status
        - code
        - error
        - message
  headers:
    XRequestId:
      description: This request's id. Include it when contacting support.
      schema:
        type: string
        format: uuid
    RateLimit:
      description: >-
        IETF draft rate-limit header:
        `"default";r=<remaining>;t=<seconds-until-reset>`. Omitted on responses
        where the limiter did not run (e.g. a pre-auth validation error, or a
        degraded limiter failing open).
      schema:
        type: string
    RateLimitPolicy:
      description: >-
        IETF draft rate-limit policy: `"default";q=<quota>;w=<window-seconds>`.
        Currently `q=600;w=60`.
      schema:
        type: string
    XRateLimitLimit:
      description: Requests allowed per window (600/minute per key).
      schema:
        type: integer
    XRateLimitRemaining:
      description: Requests remaining in the current window.
      schema:
        type: integer
    XRateLimitReset:
      description: Absolute Unix-epoch second the current window resets.
      schema:
        type: integer
    RetryAfter:
      description: >-
        Seconds to wait before retrying. Set on 429s issued by Searchable's own
        rate limiter and on `409 idempotency_in_flight`; may be absent when an
        upstream provider (e.g. Google) rate-limits.
      schema:
        type: integer
  responses:
    defaultError:
      description: >-
        Error response. `code` is the machine-readable reason — see the [error
        reference](/api/errors) for the full catalog and remediation per code.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/XRequestId'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimitPolicy'
        X-RateLimit-Limit:
          $ref: '#/components/headers/XRateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/XRateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/XRateLimitReset'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    rateLimited:
      description: >-
        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.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/XRequestId'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimitPolicy'
        X-RateLimit-Limit:
          $ref: '#/components/headers/XRateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/XRateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/XRateLimitReset'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: sea_xxxxx
      description: >-
        A Searchable API key, created under **Settings → Workspace →
        Integrations**. Send as `Authorization: Bearer sea_xxxxx`. Every key
        carries one or more scopes (`read`, `write`, `admin`) and may optionally
        be bound to a single project — see [Getting
        started](/api-reference/introduction#authentication).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.