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

# Get AI Search guidelines for a Content Editor

> Returns the AI Search guidelines for the Content Editor — a list of facts gathered from the
SERP and from the major AI engines (Google AI Overviews and AI Mode, Gemini, OpenAI,
Perplexity) for the Content Editor's main keyword and location, with the source URLs and
where each one was cited.

Each source's `cited_by` lists where the URL was found: `serp` for SERP-only sources,
otherwise a subset of `ai_mode`, `ai_overviews`, `gemini`, `openai`, `perplexity`.

`score` is the AI Search score for the current content, 0–100. `null` until the score
has been calculated; recalculated whenever the Content Editor's content changes.

`factors` breaks that score down. The `facts_coverage` factor reports how much of `facts` the
content covers, and its `covered_facts` lists which ones. The facts still missing are the rest
of `facts`. An empty `covered_facts` alongside a non-zero `value` means the score was last
calculated before this field existed, not that the content covers none of them. The
`introduction_*` factors each assess one aspect of the draft's introduction.

Returns 409 while the Content Editor is `scheduled`, `executing`, or `failed`. Once the
editor is `completed`, returns 200 with the analysis `status`; `facts` populate only when
`status` is `completed`. Poll this endpoint's `status` to detect readiness; the same
value is also surfaced as `ai_search_guidelines.status` on `GET /content_editors/:id`.

**Rate limit**: 10 requests/sec




## OpenAPI

````yaml /api/openapi-v2.json get /api/v2/workspaces/{workspace_id}/content_editors/{content_editor_id}/ai_search_guidelines
openapi: 3.0.0
info:
  description: >+
    Audit, SERP Analyzer, AI Detector, and Humanizer are not yet available in v2
    — see the v1 API docs.


    Building an LLM or agent integration?
    [/llms.txt](https://app.surferseo.com/llms.txt) is a plain-text,
    machine-readable index of this API.


    ## Authentication


    Most API requests require an `API-KEY` header with a valid API key.
    Operations that do not require authentication state that explicitly.



    ## Workspaces


    Most v2 resource endpoints are scoped to a workspace via the URL path:
    `/api/v2/workspaces/:workspace_id/...`.


    The API key must belong to an organization that owns the workspace.
    Attempting to access another organization's workspace returns `404 Not
    Found` (not `403`) to avoid leaking resource existence.



    ## Pagination


    List endpoints whose reference page documents `page` and `page_size` return
    paginated responses; the other

    list endpoints return every item with `meta.total` plus any
    endpoint-specific metadata their reference page documents. Use query
    parameters to control pagination:


    | Parameter   | Default | Max | Description                |

    |-------------|---------|-----|----------------------------|

    | `page`      | 1       | —   | Page number (1-indexed)    |

    | `page_size` | 25      | 100 | Number of items per page   |


    Response includes a `meta` object with pagination details:


    ```json

    {
      "data": [...],
      "meta": {
        "total": 156,
        "page": 1,
        "page_size": 25,
        "total_pages": 7
      }
    }

    ```



    ## Filtering


    List endpoints support filtering via bracket-notation query parameters:


    ```

    GET
    /api/v2/workspaces/123/content_editors?filter[state]=completed&filter[inserted_after]=2024-04-12T15:23:45Z

    ```


    Supported filters are documented per endpoint. Unknown filter keys are
    silently ignored. Applied filters are reflected in the response
    `meta.filters` object.



    ## Ordering


    List endpoints support ordering via `sort` and `order` query parameters:


    ```

    GET /api/v2/workspaces/123/content_editors?sort=inserted_at&order=desc

    ```


    - `sort` — field to sort by. Supported fields are documented per endpoint.
    Defaults to `inserted_at`.

    - `order` — `asc` or `desc`. Defaults to `desc`.



    ## Idempotency


    Non-idempotent operations (`POST` requests that create resources) support an
    `Idempotency-Key` header:


    ```

    POST /api/v2/workspaces/123/content_editors

    Idempotency-Key: client-generated-uuid-here

    ```


    If a request with the same key was already processed, the API answers with
    the original status code and the resource as it is now, without running the
    action again. Keys expire after 24 hours. Using the same key with a
    different request path returns `422`, a request still in progress under the
    same key returns `409`, and a failed request does not store its key, so the
    same key can retry it.



    ## Rate Limiting


    Rate limits are enforced per API key, per endpoint. When exceeded, the API
    returns `429` with a `Retry-After` header. Per-endpoint limits are
    documented on each operation.


    v2 responses additionally include `x-ratelimit-limit`,
    `x-ratelimit-remaining`, and `x-ratelimit-reset` (Unix timestamp, seconds)
    headers describing the current window state.



    ## Errors


    Newer v2 endpoints return errors in this envelope:


    ```json

    {
      "error": {
        "reason": "validation_error",
        "message": "Request validation failed",
        "details": [
          { "field": "keywords", "reason": "required" }
        ]
      }
    }

    ```


    | HTTP Status | Reason                   |
    Description                                      |

    |-------------|--------------------------|--------------------------------------------------|

    | 400         | `validation_error`       | Invalid request
    parameters                       |

    | 401         | `unauthorized`           | Missing or invalid API
    key                       |

    | 403         | `permission_denied`      | Valid key but no access,
    including plan/billing  |

    | 404         | `not_found`              | Resource does not
    exist                          |

    | 406         | `not_acceptable`         | Requested response format
    unavailable            |

    | 409         | `conflict`               | Wrong resource state or
    idempotency key in use   |

    | 413         | `content_too_large`      | Request body too
    large                           |

    | 415         | `unsupported_media_type` | Unsupported request content
    type                 |

    | 422         | `unprocessable_entity`   | Request understood but cannot be
    processed       |

    | 422         | `quota_exceeded`         | Feature enabled but credit/quota
    limit reached   |

    | 429         | `rate_limit_exceeded`    | Too many
    requests                                |

    | 500         | `internal_error`         | Unexpected server
    error                          |



    ## Webhooks


    Some asynchronous operations emit webhook events. Operations that emit
    events list the event names and payload notes in their descriptions.


    Webhook setup is organization-level. Configure an HTTPS endpoint that
    accepts POST requests and responds with a `2xx` status, then contact Surfer
    support to register the endpoint and receive a verification key.


    Surfer sends webhook requests with a `Verification-Key` header and a JSON
    body.



    ## Webhook Events


    - `content_editor.ai_article.completed`

    - `content_editor.ai_article.failed`

    - `content_editor.ai_article.waiting_for_user_input`

    - `content_editor.ai_search_score.calculated`

    - `content_editor.ai_search_score.failed`

    - `content_editor.seo_score.calculated`

    - `content_editor.seo_score.failed`

    - `content_editor.content_score.recalculated`

    - `content_editor.auto_optimize.completed`

    - `content_editor.auto_optimize.failed`

    - `content_editor.auto_optimize.cancelled`

    - `content_editor.initialization.completed`

    - `content_editor.initialization.failed`

    - `content_editor.seo_guidelines.competitors.load_more.completed`

    - `content_editor.seo_guidelines.competitors.load_more.failed`

    - `content_editor.outline.completed`

    - `content_editor.outline.failed`

  title: Surfer API
  version: v2.0
servers:
  - url: https://app.surferseo.com
    variables: {}
security: []
tags:
  - name: Workspaces
    x-displayName: Workspaces
  - description: >-
      Maintaining a legacy integration? The v1 Content Editor endpoints remain
      available.
    name: Content Editors
    x-displayName: Content Editors
  - name: AI Articles
    x-displayName: AI Articles
  - name: Auto-Optimize
    x-displayName: Auto-Optimize
  - name: SEO Guidelines
    x-displayName: SEO Guidelines
  - name: AI Search
    x-displayName: AI Search
  - name: Outline
    x-displayName: Outline
  - name: Permalinks
    x-displayName: Permalinks
  - name: Content Templates
    x-displayName: Content Templates
  - name: Custom Voices
    x-displayName: Custom Voices
  - name: Surfer Content Templates
    x-displayName: Content Template Presets
    x-group: Content Template Presets
  - description: Available in v1 only. See the v1 API docs.
    name: Audit
    x-displayName: Audit
  - description: Available in v1 only. See the v1 API docs.
    name: SERP Analyzer
    x-displayName: SERP Analyzer
  - description: Available in v1 only. See the v1 API docs.
    name: AI Detector
    x-displayName: AI Detector
  - description: Available in v1 only. See the v1 API docs.
    name: Humanizer
    x-displayName: Humanizer
paths:
  /api/v2/workspaces/{workspace_id}/content_editors/{content_editor_id}/ai_search_guidelines:
    get:
      tags:
        - AI Search
      summary: Get AI Search guidelines for a Content Editor
      description: >
        Returns the AI Search guidelines for the Content Editor — a list of
        facts gathered from the

        SERP and from the major AI engines (Google AI Overviews and AI Mode,
        Gemini, OpenAI,

        Perplexity) for the Content Editor's main keyword and location, with the
        source URLs and

        where each one was cited.


        Each source's `cited_by` lists where the URL was found: `serp` for
        SERP-only sources,

        otherwise a subset of `ai_mode`, `ai_overviews`, `gemini`, `openai`,
        `perplexity`.


        `score` is the AI Search score for the current content, 0–100. `null`
        until the score

        has been calculated; recalculated whenever the Content Editor's content
        changes.


        `factors` breaks that score down. The `facts_coverage` factor reports
        how much of `facts` the

        content covers, and its `covered_facts` lists which ones. The facts
        still missing are the rest

        of `facts`. An empty `covered_facts` alongside a non-zero `value` means
        the score was last

        calculated before this field existed, not that the content covers none
        of them. The

        `introduction_*` factors each assess one aspect of the draft's
        introduction.


        Returns 409 while the Content Editor is `scheduled`, `executing`, or
        `failed`. Once the

        editor is `completed`, returns 200 with the analysis `status`; `facts`
        populate only when

        `status` is `completed`. Poll this endpoint's `status` to detect
        readiness; the same

        value is also surfaced as `ai_search_guidelines.status` on `GET
        /content_editors/:id`.


        **Rate limit**: 10 requests/sec
      operationId: KSeoWeb.Api.V2.ContentEditors.AiSearchGuidelines.Controller.show
      parameters:
        - description: ''
          in: path
          name: workspace_id
          required: true
          schema:
            $ref: '#/components/schemas/EntityId'
        - description: ''
          in: path
          name: content_editor_id
          required: true
          schema:
            $ref: '#/components/schemas/EntityId'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiSearchGuidelines'
          description: AI Search guidelines
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '400':
          content:
            application/json:
              example:
                error:
                  details:
                    - field: keywords
                      reason: required
                  reason: validation_error
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Validation error
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '401':
          content:
            application/json:
              example:
                error:
                  details: []
                  reason: unauthorized
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Unauthorized
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '403':
          content:
            application/json:
              example:
                error:
                  details: []
                  reason: permission_denied
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Forbidden
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '404':
          content:
            application/json:
              example:
                error:
                  details: []
                  reason: not_found
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Not found
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '406':
          content:
            application/json:
              example:
                error:
                  details:
                    - allowed:
                        - application/json
                      field: accept
                      reason: unsupported
                  message: 'Accept must be one of: application/json'
                  reason: not_acceptable
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Not acceptable
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '409':
          content:
            application/json:
              example:
                error:
                  details: []
                  message: The request conflicts with the current resource state.
                  reason: conflict
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Content editor not completed
          headers:
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
        '429':
          content:
            application/json:
              example:
                error:
                  details:
                    - retry_after: 30
                  reason: rate_limit_exceeded
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Rate limit exceeded
          headers:
            Retry-After:
              description: Seconds the client should wait before retrying the request.
              schema:
                example: 30
                type: integer
              style: simple
            x-ratelimit-limit:
              description: >-
                Maximum number of requests allowed in the current window for
                this endpoint and API key.
              schema:
                example: 10
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: >-
                Requests remaining in the current window. `0` means the next
                request will be rate-limited.
              schema:
                example: 7
                type: integer
              style: simple
            x-ratelimit-reset:
              description: Unix timestamp (seconds) at which the current window resets.
              schema:
                example: 1714838400
                type: integer
              style: simple
      callbacks: {}
      security:
        - API Key: []
components:
  schemas:
    EntityId:
      example: 123
      minimum: 1
      title: EntityId
      type: integer
    AiSearchGuidelines:
      allOf:
        - $ref: '#/components/schemas/V2.Timestamps'
      properties:
        factors:
          description: >-
            What the `score` is made of. Empty until the score has been
            calculated.
          example:
            - covered_facts:
                - Surfer SEO is an SEO platform with a Content Editor.
              name: facts_coverage
              value: 62
            - found: true
              name: introduction_covered_topics
          items:
            $ref: '#/components/schemas/AiSearchGuidelinesScoreFactor'
          type: array
        facts:
          description: Empty until `status` is `completed`.
          items:
            $ref: '#/components/schemas/AiSearchGuidelinesFact'
          type: array
        id:
          $ref: '#/components/schemas/EntityId'
        score:
          description: >-
            AI Search score, 0–100. `null` until calculation finishes;
            recalculated whenever the Content Editor's content changes.
          example: 62
          nullable: true
          type: integer
        status:
          description: >-
            `executing` while SERP analysis or LLM merging is in progress.
            `completed` once both have settled and `facts` is final — LLM-only
            sources may be missing when the LLM merge failed. `failed` if SERP
            analysis failed.
          enum:
            - executing
            - completed
            - failed
          type: string
      required:
        - id
        - status
        - score
        - factors
        - facts
      title: AiSearchGuidelines
      type: object
    ErrorResponse:
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetails'
      required:
        - error
      title: ErrorResponse
      type: object
    V2.Timestamps:
      properties:
        inserted_at:
          example: '2024-04-12T15:23:45Z'
          format: date-time
          type: string
        updated_at:
          example: '2024-06-01T09:17:33Z'
          format: date-time
          type: string
      required:
        - inserted_at
      title: V2.Timestamps
      type: object
    AiSearchGuidelinesScoreFactor:
      description: >-
        One component of the AI Search score. `name` determines which shape it
        takes.
      discriminator:
        mapping:
          facts_coverage: '#/components/schemas/AiSearchGuidelinesFactsCoverageFactor'
          introduction_covered_topics: '#/components/schemas/AiSearchGuidelinesIntroductionFactor'
          introduction_early_query_answer: '#/components/schemas/AiSearchGuidelinesIntroductionFactor'
          introduction_target_audience: '#/components/schemas/AiSearchGuidelinesIntroductionFactor'
          introduction_topic_relevance: '#/components/schemas/AiSearchGuidelinesIntroductionFactor'
        propertyName: name
      oneOf:
        - $ref: '#/components/schemas/AiSearchGuidelinesFactsCoverageFactor'
        - $ref: '#/components/schemas/AiSearchGuidelinesIntroductionFactor'
      title: AiSearchGuidelinesScoreFactor
    AiSearchGuidelinesFact:
      properties:
        fact:
          example: Surfer SEO is an SEO platform with a Content Editor.
          type: string
        id:
          example: f1e2c3d4-5678-49ab-9cde-0123456789ab
          format: uuid
          type: string
        sources:
          items:
            $ref: '#/components/schemas/AiSearchGuidelinesFactSource'
          type: array
      required:
        - id
        - fact
        - sources
      title: AiSearchGuidelinesFact
      type: object
    ErrorDetails:
      properties:
        details:
          description: Structured details; shape depends on `reason`.
          items:
            type: object
          type: array
        message:
          description: Optional human-readable context.
          type: string
        reason:
          description: Machine-readable error key.
          type: string
      required:
        - reason
        - details
      title: ErrorDetails
      type: object
    AiSearchGuidelinesFactsCoverageFactor:
      additionalProperties: false
      description: How much of the AI Search facts the content already states.
      properties:
        covered_facts:
          description: >-
            The facts the content covers, as text. Empty when the content covers
            none of them. Also empty for a score last calculated before this
            field existed. The next recalculation fills them in.
          example:
            - Surfer SEO is an SEO platform with a Content Editor.
          items:
            type: string
          type: array
        name:
          enum:
            - facts_coverage
          example: facts_coverage
          type: string
        value:
          description: Share of the facts the content covers, 0–100.
          example: 62
          maximum: 100
          minimum: 0
          type: integer
      required:
        - name
        - value
        - covered_facts
      title: AiSearchGuidelinesFactsCoverageFactor
      type: object
    AiSearchGuidelinesIntroductionFactor:
      additionalProperties: false
      description: One aspect of the draft's introduction.
      properties:
        found:
          description: Whether the introduction satisfies this factor.
          example: true
          type: boolean
        name:
          enum:
            - introduction_covered_topics
            - introduction_target_audience
            - introduction_topic_relevance
            - introduction_early_query_answer
          example: introduction_covered_topics
          type: string
      required:
        - name
        - found
      title: AiSearchGuidelinesIntroductionFactor
      type: object
    AiSearchGuidelinesFactSource:
      properties:
        cited_by:
          description: >-
            Where this URL was cited for the fact. `serp` indicates the URL came
            only from the SERP scrape; otherwise a subset of `ai_mode`,
            `ai_overviews`, `gemini`, `openai`, `perplexity`.
          example:
            - openai
            - perplexity
          items:
            enum:
              - serp
              - ai_mode
              - ai_overviews
              - gemini
              - openai
              - perplexity
            type: string
          type: array
        url:
          description: >-
            `null` when the fact was stated by an AI model without citing any
            source.
          example: https://example.com/article
          nullable: true
          type: string
      required:
        - url
        - cited_by
      title: AiSearchGuidelinesFactSource
      type: object
  securitySchemes:
    API Key:
      in: header
      name: API-KEY
      type: apiKey

````

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