# Prompts

Source: https://ceyo.ai/docs/signal/prompts

### Prompts

Create and manage the monitored questions used for visibility tracking.

**Scope:** Project

### List prompts

`GET /projects/{project_id}/visibility/prompts`

Returns paginated prompts and visibility metrics for the selected project.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `start` | date | Optional; Default: 6 days before end | First metrics date in YYYY-MM-DD format. The inclusive range may span at most 3 months. |
| `end` | date | Optional; Default: Today | Last metrics date in YYYY-MM-DD format. The inclusive range may span at most 3 months. |
| `models` | string | Optional; Default: All enabled models | Comma-separated or repeated model keys. |
| `topic_ids` | string | Optional | Comma-separated or repeated topic UUIDs. |
| `competitor_ids` | string | Optional | Tracked competitor UUIDs that must be mentioned. |
| `sentiments` | string | Optional | Comma-separated negative, neutral, or positive labels. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison | Optional | Restrict prompts to one category. |
| `q` | string | Optional | Search prompt content and topic names. |
| `status` | active \| archived | Optional; Default: active | Select active prompts or archived prompts. |
| `sort` | created\_at \| prompt \| topic \| visibility \| position \| volume | Optional; Default: created\_at | Field used to order the result. |
| `sort_direction` | asc \| desc | Optional; Default: desc | Sort direction. |
| `page` | integer | Optional; Default: 1 | 1-based page number. |
| `per_page` | integer | Optional; Default: 25 | Prompts per page. Maximum: 100. |

#### Response envelope

`project_id`:**uuid**`prompts`:**Prompt\[\]**`start`:**date**`end`:**date**`models`:**string\[\]**`pagination`:**Pagination**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved Ceyo project identifier. |
| `prompts` | Prompt\[\] |  | Paginated prompts matching the filters. |
| `start` | date |  | Resolved metrics start date. |
| `end` | date |  | Resolved metrics end date. |
| `models` | string\[\] |  | Model keys included in metric calculations. |
| `pagination` | Pagination |  | Prompt pagination metadata. |

#### Prompt

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Unique prompt identifier. |
| `topic_id` | uuid |  | Topic that contains the prompt. |
| `topic_name` | string |  | Current name of the containing topic. |
| `content` | string |  | Question sent to configured AI models. Maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Stable snake\_case intent category. |
| `city_override` | string \| null |  | Prompt-specific city. Null means the city is inherited from the selected scope. |
| `country_override` | string \| null |  | Prompt-specific country. Null means the country is inherited from the selected scope; present together with country\_code\_override. |
| `country_code_override` | string \| null |  | Prompt-specific uppercase ISO 3166-1 alpha-2 country code. Null means the code is inherited; present together with country\_override. |
| `archived_at` | datetime \| null |  | Archive time. Null means the prompt is active. |
| `created_at` | datetime |  | Prompt creation time in ISO 8601 format. |
| `metrics` | PromptMetrics \| null |  | Visibility metrics for the requested date and model filters. |

#### PromptMetrics

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `primary_mentions` | integer |  | Responses that mentioned the primary tracked brand. |
| `visibility_percentage` | number |  | Share of responses that mentioned the primary tracked brand. |
| `visibility_trend_pp` | number \| null |  | Percentage-point change from the preceding equal-length period. |
| `average_position` | number \| null |  | Average 1-based primary-brand position when mentioned. |
| `position_trend` | number \| null |  | Average-position change from the preceding period. |
| `average_position_trend` | number \| null |  | Change in average position from the preceding comparison window. |
| `average_sentiment` | number \| null |  | Average primary-brand sentiment score. |
| `sentiment_counts` | SentimentCounts |  | Response counts keyed by negative, neutral, and positive. |
| `citations` | integer |  | Citation occurrences across matching responses. |
| `competitor_mentions` | Record<string, integer> |  | Mention counts keyed by tracked competitor name. |

#### SentimentCounts

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `negative` | integer |  | Negative responses. |
| `neutral` | integer |  | Neutral responses. |
| `positive` | integer |  | Positive responses. |

#### Pagination

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `page` | integer |  | Current 1-based page. |
| `per_page` | integer |  | Records requested per page. |
| `total` | integer |  | Total records matching the filters. |
| `total_pages` | integer |  | Total available pages. |

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts?start=2026-07-24&end=2026-07-30&models=chatgpt,perplexity&status=active&page=1' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "project_id": "e6c96c98-d777-40e0-94ec-48931f57782f",
  "prompts": [
    {
      "id": "4de5e484-ce6a-4e45-ad7c-bd48db2549af",
      "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
      "topic_name": "AI visibility platforms",
      "content": "Which platforms help brands measure visibility in AI answers?",
      "category": "organic_search",
      "city_override": null,
      "country_override": null,
      "country_code_override": null,
      "archived_at": null,
      "created_at": "2026-07-20T08:35:00Z",
      "metrics": {
        "primary_mentions": 8,
        "visibility_percentage": 57.14,
        "visibility_trend_pp": 7.14,
        "average_position": 2.25,
        "position_trend": -0.5,
        "average_position_trend": -0.5,
        "average_sentiment": 7.6,
        "sentiment_counts": {
          "negative": 1,
          "neutral": 4,
          "positive": 9
        },
        "citations": 22,
        "competitor_mentions": {
          "Example competitor": 6
        }
      }
    }
  ],
  "start": "2026-07-24",
  "end": "2026-07-30",
  "models": [
    "chatgpt",
    "perplexity"
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 36,
    "total_pages": 2
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Create prompt

`POST /projects/{project_id}/visibility/prompts`

Creates and activates one prompt for visibility tracking across the enabled models.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `topic_id` | uuid |  | Topic in this scope. Required when creating a prompt. |
| `content` | string |  | Prompt question. Required; maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Prompt category. Defaults to general when creating. |
| `city_override` | string \| null |  | Optional create-only city override; maximum 200 characters. Omit or send null to inherit the scope city. |
| `country_override` | string \| null |  | Country name for a location override; must be provided with country\_code\_override. Maximum 200 characters. |
| `country_code_override` | string \| null |  | Uppercase two-letter code for a location override; must be provided with country\_override. |

> **Location override**
>
> country\_override and country\_code\_override must be supplied together. city\_override is optional. Effective geography combines these values with the scope defaults. Language comes from the selected scope.

#### Response envelope

`project_id`:**uuid**`prompt`:**Prompt**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved Ceyo project identifier. |
| `prompt` | Prompt |  | Created and activated prompt. |

#### Prompt

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Unique prompt identifier. |
| `topic_id` | uuid |  | Topic that contains the prompt. |
| `topic_name` | string |  | Current name of the containing topic. |
| `content` | string |  | Question sent to configured AI models. Maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Stable snake\_case intent category. |
| `city_override` | string \| null |  | Prompt-specific city. Null means the city is inherited from the selected scope. |
| `country_override` | string \| null |  | Prompt-specific country. Null means the country is inherited from the selected scope; present together with country\_code\_override. |
| `country_code_override` | string \| null |  | Prompt-specific uppercase ISO 3166-1 alpha-2 country code. Null means the code is inherited; present together with country\_override. |
| `archived_at` | datetime \| null |  | Archive time. Null means the prompt is active. |
| `created_at` | datetime |  | Prompt creation time in ISO 8601 format. |
| `metrics` | PromptMetrics \| null |  | Visibility metrics for the requested date and model filters. |

#### PromptMetrics

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `primary_mentions` | integer |  | Responses that mentioned the primary tracked brand. |
| `visibility_percentage` | number |  | Share of responses that mentioned the primary tracked brand. |
| `visibility_trend_pp` | number \| null |  | Percentage-point change from the preceding equal-length period. |
| `average_position` | number \| null |  | Average 1-based primary-brand position when mentioned. |
| `position_trend` | number \| null |  | Average-position change from the preceding period. |
| `average_position_trend` | number \| null |  | Change in average position from the preceding comparison window. |
| `average_sentiment` | number \| null |  | Average primary-brand sentiment score. |
| `sentiment_counts` | SentimentCounts |  | Response counts keyed by negative, neutral, and positive. |
| `citations` | integer |  | Citation occurrences across matching responses. |
| `competitor_mentions` | Record<string, integer> |  | Mention counts keyed by tracked competitor name. |

#### SentimentCounts

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `negative` | integer |  | Negative responses. |
| `neutral` | integer |  | Neutral responses. |
| `positive` | integer |  | Positive responses. |

#### Request and response

```curl
curl --request POST \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts' \
  --header 'Authorization: Bearer ceyo_platform_...' \
  --header 'Content-Type: application/json' \
  --data '{"topic_id":"ab20526b-6bb2-436c-8c93-5bf77ea43848","content":"Which platforms help brands measure visibility in AI answers?","category":"organic_search"}'
```

```json
{
  "project_id": "e6c96c98-d777-40e0-94ec-48931f57782f",
  "prompt": {
    "id": "4de5e484-ce6a-4e45-ad7c-bd48db2549af",
    "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
    "topic_name": "AI visibility platforms",
    "content": "Which platforms help brands measure visibility in AI answers?",
    "category": "organic_search",
    "city_override": null,
    "country_override": null,
    "country_code_override": null,
    "archived_at": null,
    "created_at": "2026-07-20T08:35:00Z",
    "metrics": null
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Bulk create prompts

`POST /projects/{project_id}/visibility/prompts/bulk_create`

Creates and activates up to 100 prompts atomically. Any invalid row or capacity failure rejects the entire request.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |

#### Request body

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `prompts` | PromptInput\[\] |  | Required array containing 1–100 prompt rows. |

#### PromptInput

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `topic_id` | uuid |  | Topic in this scope. Required when creating a prompt. |
| `content` | string |  | Prompt question. Required; maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Prompt category. Defaults to general when creating. |
| `city_override` | string \| null |  | Optional create-only city override; maximum 200 characters. Omit or send null to inherit the scope city. |
| `country_override` | string \| null |  | Country name for a location override; must be provided with country\_code\_override. Maximum 200 characters. |
| `country_code_override` | string \| null |  | Uppercase two-letter code for a location override; must be provided with country\_override. |

> **Location override**
>
> Each row must supply country\_override and country\_code\_override together. city\_override is optional. Effective geography combines these values with the scope defaults; language is inherited.

#### Response envelope

`project_id`:**uuid**`prompts`:**Prompt\[\]**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved Ceyo project identifier. |
| `prompts` | Prompt\[\] |  | Created and activated prompts in request order. |

#### Prompt

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Unique prompt identifier. |
| `topic_id` | uuid |  | Topic that contains the prompt. |
| `topic_name` | string |  | Current name of the containing topic. |
| `content` | string |  | Question sent to configured AI models. Maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Stable snake\_case intent category. |
| `city_override` | string \| null |  | Prompt-specific city. Null means the city is inherited from the selected scope. |
| `country_override` | string \| null |  | Prompt-specific country. Null means the country is inherited from the selected scope; present together with country\_code\_override. |
| `country_code_override` | string \| null |  | Prompt-specific uppercase ISO 3166-1 alpha-2 country code. Null means the code is inherited; present together with country\_override. |
| `archived_at` | datetime \| null |  | Archive time. Null means the prompt is active. |
| `created_at` | datetime |  | Prompt creation time in ISO 8601 format. |
| `metrics` | PromptMetrics \| null |  | Visibility metrics for the requested date and model filters. |

#### PromptMetrics

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `primary_mentions` | integer |  | Responses that mentioned the primary tracked brand. |
| `visibility_percentage` | number |  | Share of responses that mentioned the primary tracked brand. |
| `visibility_trend_pp` | number \| null |  | Percentage-point change from the preceding equal-length period. |
| `average_position` | number \| null |  | Average 1-based primary-brand position when mentioned. |
| `position_trend` | number \| null |  | Average-position change from the preceding period. |
| `average_position_trend` | number \| null |  | Change in average position from the preceding comparison window. |
| `average_sentiment` | number \| null |  | Average primary-brand sentiment score. |
| `sentiment_counts` | SentimentCounts |  | Response counts keyed by negative, neutral, and positive. |
| `citations` | integer |  | Citation occurrences across matching responses. |
| `competitor_mentions` | Record<string, integer> |  | Mention counts keyed by tracked competitor name. |

#### SentimentCounts

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `negative` | integer |  | Negative responses. |
| `neutral` | integer |  | Neutral responses. |
| `positive` | integer |  | Positive responses. |

#### Request and response

```curl
curl --request POST \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts/bulk_create' \
  --header 'Authorization: Bearer ceyo_platform_...' \
  --header 'Content-Type: application/json' \
  --data '{"prompts":[{"topic_id":"ab20526b-6bb2-436c-8c93-5bf77ea43848","content":"Which platforms help brands measure visibility in AI answers?","category":"organic_search"},{"topic_id":"ab20526b-6bb2-436c-8c93-5bf77ea43848","content":"How do AI visibility platforms compare?","category":"competitor_comparison"}]}'
```

```json
{
  "project_id": "e6c96c98-d777-40e0-94ec-48931f57782f",
  "prompts": [
    {
      "id": "4de5e484-ce6a-4e45-ad7c-bd48db2549af",
      "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
      "topic_name": "AI visibility platforms",
      "content": "Which platforms help brands measure visibility in AI answers?",
      "category": "organic_search",
      "city_override": null,
      "country_override": null,
      "country_code_override": null,
      "archived_at": null,
      "created_at": "2026-07-20T08:35:00Z",
      "metrics": null
    },
    {
      "id": "ab7d6157-ca42-4d43-b02c-edeea5911475",
      "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
      "topic_name": "AI visibility platforms",
      "content": "How do AI visibility platforms compare?",
      "category": "competitor_comparison",
      "city_override": null,
      "country_override": null,
      "country_code_override": null,
      "archived_at": null,
      "created_at": "2026-07-20T08:35:00Z",
      "metrics": null
    }
  ]
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Get prompt

`GET /projects/{project_id}/visibility/prompts/{prompt_id}`

Returns one active or archived prompt in the selected project, with metrics for the requested period and enabled-model context.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `prompt_id` | uuid | Required | Prompt identifier. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `start` | date | Optional; Default: 6 days before end | First metrics date in YYYY-MM-DD format. The inclusive range may span at most 3 months. |
| `end` | date | Optional; Default: Today | Last metrics date in YYYY-MM-DD format. The inclusive range may span at most 3 months. |
| `models` | string | Optional; Default: All enabled models | Comma-separated or repeated model keys. |

#### Response envelope

`project_id`:**uuid**`prompt`:**Prompt**`start`:**date**`end`:**date**`models`:**string\[\]**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved Ceyo project identifier. |
| `prompt` | Prompt |  | Requested prompt and metrics. |
| `start` | date |  | Resolved metrics start. |
| `end` | date |  | Resolved metrics end. |
| `models` | string\[\] |  | Models included in metrics. |

#### Prompt

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Unique prompt identifier. |
| `topic_id` | uuid |  | Topic that contains the prompt. |
| `topic_name` | string |  | Current name of the containing topic. |
| `content` | string |  | Question sent to configured AI models. Maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Stable snake\_case intent category. |
| `city_override` | string \| null |  | Prompt-specific city. Null means the city is inherited from the selected scope. |
| `country_override` | string \| null |  | Prompt-specific country. Null means the country is inherited from the selected scope; present together with country\_code\_override. |
| `country_code_override` | string \| null |  | Prompt-specific uppercase ISO 3166-1 alpha-2 country code. Null means the code is inherited; present together with country\_override. |
| `archived_at` | datetime \| null |  | Archive time. Null means the prompt is active. |
| `created_at` | datetime |  | Prompt creation time in ISO 8601 format. |
| `metrics` | PromptMetrics \| null |  | Visibility metrics for the requested date and model filters. |

#### PromptMetrics

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `primary_mentions` | integer |  | Responses that mentioned the primary tracked brand. |
| `visibility_percentage` | number |  | Share of responses that mentioned the primary tracked brand. |
| `visibility_trend_pp` | number \| null |  | Percentage-point change from the preceding equal-length period. |
| `average_position` | number \| null |  | Average 1-based primary-brand position when mentioned. |
| `position_trend` | number \| null |  | Average-position change from the preceding period. |
| `average_position_trend` | number \| null |  | Change in average position from the preceding comparison window. |
| `average_sentiment` | number \| null |  | Average primary-brand sentiment score. |
| `sentiment_counts` | SentimentCounts |  | Response counts keyed by negative, neutral, and positive. |
| `citations` | integer |  | Citation occurrences across matching responses. |
| `competitor_mentions` | Record<string, integer> |  | Mention counts keyed by tracked competitor name. |

#### SentimentCounts

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `negative` | integer |  | Negative responses. |
| `neutral` | integer |  | Neutral responses. |
| `positive` | integer |  | Positive responses. |

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts/{prompt_id}?start=2026-07-24&end=2026-07-30' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "project_id": "e6c96c98-d777-40e0-94ec-48931f57782f",
  "prompt": {
    "id": "4de5e484-ce6a-4e45-ad7c-bd48db2549af",
    "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
    "topic_name": "AI visibility platforms",
    "content": "Which platforms help brands measure visibility in AI answers?",
    "category": "organic_search",
    "city_override": null,
    "country_override": null,
    "country_code_override": null,
    "archived_at": null,
    "created_at": "2026-07-20T08:35:00Z",
    "metrics": {
      "primary_mentions": 8,
      "visibility_percentage": 57.14,
      "visibility_trend_pp": 7.14,
      "average_position": 2.25,
      "position_trend": -0.5,
      "average_position_trend": -0.5,
      "average_sentiment": 7.6,
      "sentiment_counts": {
        "negative": 1,
        "neutral": 4,
        "positive": 9
      },
      "citations": 22,
      "competitor_mentions": {
        "Example competitor": 6
      }
    }
  },
  "start": "2026-07-24",
  "end": "2026-07-30",
  "models": [
    "chatgpt",
    "perplexity"
  ]
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Archive prompt

`DELETE /projects/{project_id}/visibility/prompts/{prompt_id}`

Archives an active prompt and stops it consuming active capacity. Historical response data remains available. A successful archive has no response body.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `prompt_id` | uuid | Required | Prompt identifier. |

#### Response

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `204` | No Content |  | Prompt was archived successfully. |

> **Reversible archive**
>
> Archive hides a prompt from active monitoring but preserves its data. Use restore to activate it again. Permanent deletion is a separate, irreversible endpoint.

#### Request and response

```curl
curl --request DELETE \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts/{prompt_id}' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
HTTP/1.1 204 No Content
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Restore prompt

`POST /projects/{project_id}/visibility/prompts/{prompt_id}/restore`

Restores and reactivates an archived prompt after checking active capacity only. Restore does not consume daily activations and does not schedule a visibility run.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `prompt_id` | uuid | Required | Prompt identifier. |

#### Response envelope

`project_id`:**uuid**`prompt`:**Prompt**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | uuid |  | Resolved Ceyo project identifier. |
| `prompt` | Prompt |  | Restored and reactivated prompt. |

#### Prompt

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Unique prompt identifier. |
| `topic_id` | uuid |  | Topic that contains the prompt. |
| `topic_name` | string |  | Current name of the containing topic. |
| `content` | string |  | Question sent to configured AI models. Maximum 20,000 characters. |
| `category` | general \| organic\_search \| brand\_sentiment \| competitor\_comparison |  | Stable snake\_case intent category. |
| `city_override` | string \| null |  | Prompt-specific city. Null means the city is inherited from the selected scope. |
| `country_override` | string \| null |  | Prompt-specific country. Null means the country is inherited from the selected scope; present together with country\_code\_override. |
| `country_code_override` | string \| null |  | Prompt-specific uppercase ISO 3166-1 alpha-2 country code. Null means the code is inherited; present together with country\_override. |
| `archived_at` | datetime \| null |  | Archive time. Null means the prompt is active. |
| `created_at` | datetime |  | Prompt creation time in ISO 8601 format. |
| `metrics` | PromptMetrics \| null |  | Visibility metrics for the requested date and model filters. |

#### PromptMetrics

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `primary_mentions` | integer |  | Responses that mentioned the primary tracked brand. |
| `visibility_percentage` | number |  | Share of responses that mentioned the primary tracked brand. |
| `visibility_trend_pp` | number \| null |  | Percentage-point change from the preceding equal-length period. |
| `average_position` | number \| null |  | Average 1-based primary-brand position when mentioned. |
| `position_trend` | number \| null |  | Average-position change from the preceding period. |
| `average_position_trend` | number \| null |  | Change in average position from the preceding comparison window. |
| `average_sentiment` | number \| null |  | Average primary-brand sentiment score. |
| `sentiment_counts` | SentimentCounts |  | Response counts keyed by negative, neutral, and positive. |
| `citations` | integer |  | Citation occurrences across matching responses. |
| `competitor_mentions` | Record<string, integer> |  | Mention counts keyed by tracked competitor name. |

#### SentimentCounts

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `negative` | integer |  | Negative responses. |
| `neutral` | integer |  | Neutral responses. |
| `positive` | integer |  | Positive responses. |

#### Request and response

```curl
curl --request POST \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts/{prompt_id}/restore' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "project_id": "e6c96c98-d777-40e0-94ec-48931f57782f",
  "prompt": {
    "id": "4de5e484-ce6a-4e45-ad7c-bd48db2549af",
    "topic_id": "ab20526b-6bb2-436c-8c93-5bf77ea43848",
    "topic_name": "AI visibility platforms",
    "content": "Which platforms help brands measure visibility in AI answers?",
    "category": "organic_search",
    "city_override": null,
    "country_override": null,
    "country_code_override": null,
    "archived_at": null,
    "created_at": "2026-07-20T08:35:00Z",
    "metrics": null
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Delete prompt permanently

`DELETE /projects/{project_id}/visibility/prompts/{prompt_id}/permanent`

Starts irreversible asynchronous deletion of a prompt and its dependent visibility data. Archive the prompt instead if it may be needed again.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `prompt_id` | uuid | Required | Prompt identifier. |

> **Irreversible delete**
>
> The request returns before background deletion completes.

#### Request and response

```curl
curl --request DELETE \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/visibility/prompts/{prompt_id}/permanent' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
HTTP/1.1 202 Accepted
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "name",
        "message": "must be present"
      }
    ],
    "request_id": "req_01K1GP6J8QQFZ4D2B6C5A9V3TS"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_request \| invalid\_date\_range \| range\_too\_large |  | A prompt filter, model, identifier, or metrics date range is invalid, or the range exceeds three months. |
| `401` | invalid\_api\_key |  | Authorization is absent or invalid. |
| `403` | forbidden |  | The API key cannot manage this visibility scope. |
| `404` | not\_found |  | The project, location, or prompt was not found. |
| `409` | conflict |  | The requested lifecycle operation conflicts with current state. |
| `422` | validation\_failed \| prompt\_limit\_reached \| daily\_prompt\_activation\_limit\_reached |  | Input is invalid, a suggested-prompt status is unsupported, capacity is exhausted, or a bulk request exceeds 100 rows. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |
