Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 127 additions & 11 deletions docs/index.html

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/openapi/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ paths:
$ref: './serenity-api.yaml#/v2-serenity-market-tracking-trends'
/v2/orgs/{spaceCatId}/brands/{brandId}/serenity/brand-presence/sentiment-overview:
$ref: './serenity-api.yaml#/v2-serenity-brand-presence-sentiment-overview'
/v2/orgs/{spaceCatId}/brands/{brandId}/serenity/brand-presence/topics:
$ref: './serenity-api.yaml#/v2-serenity-brand-presence-topics'
/v2/orgs/{spaceCatId}/brands/{brandId}/serenity/brand-presence/topics/{topicId}/prompts:
$ref: './serenity-api.yaml#/v2-serenity-brand-presence-topic-prompts'
/v2/orgs/{spaceCatId}/brands/{brandId}/serenity/brand-presence/stats:
$ref: './serenity-api.yaml#/v2-serenity-brand-presence-stats'
/organizations/{organizationId}/sites:
Expand Down
131 changes: 131 additions & 0 deletions docs/openapi/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11648,6 +11648,137 @@ SerenityBrandPresenceSentimentOverview:
description: Stubbed empty (parity with the legacy contract).
items: { type: object }

SerenityBrandPresenceTopics:
type: object
description: |
Data Insights per-topic table, aggregated server-side from the Semrush "Prompts
by Topic" element (78864493) grouped by topic. `totalCount` is the number of topics.
required: [topics, totalCount]
properties:
totalCount:
type: integer
description: Number of topics returned.
topics:
type: array
description: One entry per topic, ordered by total search volume descending.
items:
type: object
required:
- topic
- promptCount
- brandMentions
- brandCitations
- volume
- averageVisibilityScore
properties:
topic:
type: string
description: Topic name (the identifier used by the drill-down `:topicId`).
promptCount:
type: integer
description: |
Number of prompts in the topic, from grouping the (unfiltered) prompts
element by topic. Reflects the returned population; it can lag the
per-topic drill-down's `totalCount` only if the workspace exceeds the
element's row cap (not observed at current data volumes).
brandMentions:
type: integer
description: Sum of brand mentions across the topic's prompts.
brandCitations:
type: integer
description: Sum of citations across the topic's prompts.
volume:
type: integer
description: Sum of search volume across the topic's prompts (feeds UI popularity bucketing).
averageVisibilityScore:
type: number
description: Mean visibility (0-100) over all prompts in the topic.
averagePosition:
type: [number, 'null']
description: |
Mean rank position over prompts that are ranked, or `null` when the topic
has no ranked prompt (the element's `-1` sentinel is excluded, not averaged).
averageSentiment:
type: [number, 'null']
description: |
Mean sentiment (0-1) over prompts that have sentiment, or `null` when none do.
prompts:
type: array
description: |
The topic's own per-prompt rows (sorted by volume desc), embedded so the
eager Data Insights table renders rows + drill-down from a single call.
items: { $ref: '#/SerenityBrandPresenceTopicPromptRow' }

SerenityBrandPresenceTopicPrompts:
type: object
description: |
Per-prompt drill-down for a single Data Insights topic, sourced from the
Semrush "Prompts by Topic" element (78864493). One `prompts[]` entry per
prompt in the topic; `totalCount` is the full pre-pagination count and
`page`/`pageSize` echo the applied server-side slice.
required: [topicId, prompts, totalCount]
properties:
topicId:
type: string
description: The topic name this drill-down is scoped to (echoes the decoded `:topicId`).
totalCount:
type: integer
description: Total prompts for the topic before pagination.
page:
type: integer
description: Zero-based page index applied.
pageSize:
type: integer
description: Page size applied.
prompts:
type: array
description: One entry per prompt in this topic (for the current page).
items: { $ref: '#/SerenityBrandPresenceTopicPromptRow' }

SerenityBrandPresenceTopicPromptRow:
type: object
description: A single prompt row within a Data Insights topic.
required:
- prompt
- topic
- mentions
- citations
- visibility
- volume
properties:
prompt:
type: string
description: The prompt text.
topic:
type: string
description: The topic name this prompt belongs to.
primaryIntent:
type: string
description: Semrush primary intent (e.g. informational, commercial, transactional).
region:
type: string
description: Semrush project title for the prompt's market (e.g. `US-en`).
mentions:
type: integer
description: Brand mentions for this prompt.
citations:
type: integer
description: Citations for this prompt.
visibility:
type: number
description: Visibility score (0-100).
position:
type: [number, 'null']
description: |
Average rank position, or `null` when unranked (the element's `-1`
"not answered / not ranked" sentinel is normalized to `null`).
sentiment:
type: [number, 'null']
description: Sentiment score (0-1), or `null` when the prompt has no sentiment.
volume:
type: integer
description: Search volume for the prompt.

SerenityFilterDimensionItem:
type: object
description: |
Expand Down
187 changes: 187 additions & 0 deletions docs/openapi/serenity-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,193 @@ v2-serenity-brand-presence-sentiment-overview:
schema: { $ref: './schemas.yaml#/SerenityErrorResponse' }
'500': { $ref: './responses.yaml#/500' }

v2-serenity-brand-presence-topics:
parameters:
- name: spaceCatId
in: path
required: true
description: SpaceCat Organization ID (UUID)
schema:
type: string
format: uuid
- name: brandId
in: path
required: true
description: Brand ID (UUID-only on the /serenity/* surface)
schema:
type: string
format: uuid
get:
tags: [serenity]
summary: Data Insights per-topic table
description: |
Returns one row per topic with per-topic aggregates (prompt count, total brand
mentions/citations, total volume, and average visibility/position/sentiment).
Built from the Semrush "Prompts by Topic" element (78864493) grouped by topic
server-side — the same element that backs the per-prompt drill-down.

Brand-scoped via the brand's Semrush sub-workspace (resolved from `:brandId`);
`region` (when not `all`) resolves to a Semrush `project_id` server-side, and
`model`/`platform` translate to a Semrush model server-side. Returns the full
topic list (no server-side pagination); the table paginates client-side.
operationId: listSerenityBrandPresenceTopics
security:
- ims_key: []
parameters:
- name: startDate
in: query
required: false
description: Inclusive range start (YYYY-MM-DD). Optional; both dates required together.
schema: { type: string, format: date }
- name: endDate
in: query
required: false
description: Inclusive range end (YYYY-MM-DD). Optional; both dates required together.
schema: { type: string, format: date }
- name: model
in: query
required: false
description: |
AI model to scope to. Accepts a Semrush Elements model name directly, or a
SpaceCat/UI platform code (translated server-side). Defaults to `search-gpt`.
schema: { type: string }
- name: platform
in: query
required: false
description: Legacy alias for `model`; `model` takes precedence when both are given.
schema: { type: string }
- name: region
in: query
required: false
description: |
UI region code (e.g. `US`) resolved server-side to a Semrush `project_id`.
`all` or omitted → across the brand's markets.
schema: { type: string }
responses:
'200':
description: Topic table retrieved.
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityBrandPresenceTopics' }
'400': { $ref: './responses.yaml#/400' }
'403':
description: Caller lacks access to the organization.
'404':
description: Organization not found, brand not found for this organization, the brand has no Semrush sub-workspace, or no Semrush market resolves for the requested region.
'502':
description: Upstream returned a non-2xx response.
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityErrorResponse' }
'503':
description: PostgREST client not available (required to resolve the brand's Semrush workspace before the element call).
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityErrorResponse' }
'500': { $ref: './responses.yaml#/500' }

v2-serenity-brand-presence-topic-prompts:
parameters:
- name: spaceCatId
in: path
required: true
description: SpaceCat Organization ID (UUID)
schema:
type: string
format: uuid
- name: brandId
in: path
required: true
description: Brand ID (UUID-only on the /serenity/* surface)
schema:
type: string
format: uuid
- name: topicId
in: path
required: true
description: |
The topic NAME (URL-encoded). Semrush topics have no UUID — the topic name
IS the identifier, scoped upstream via the element's `CBF_topic` filter.
schema: { type: string }
get:
tags: [serenity]
summary: Per-prompt drill-down for a single Data Insights topic
description: |
Returns the individual prompts belonging to one topic, with their per-prompt
mentions, citations, visibility, position, sentiment, volume and primary intent.
Sourced from the Semrush "Prompts by Topic" element (78864493) — the same rich
element that backs the topic table — scoped by `CBF_topic` (the topic name).

Brand-scoped via the brand's Semrush sub-workspace (resolved from `:brandId`);
`region` (when not `all`) resolves to a Semrush `project_id` server-side, and
`model`/`platform` translate to a Semrush model server-side. Pagination is
applied server-side over the full result (Semrush has no native paging).
operationId: listSerenityBrandPresenceTopicPrompts
security:
- ims_key: []
parameters:
- name: startDate
in: query
required: false
description: Inclusive range start (YYYY-MM-DD). Optional; both dates required together.
schema: { type: string, format: date }
- name: endDate
in: query
required: false
description: Inclusive range end (YYYY-MM-DD). Optional; both dates required together.
schema: { type: string, format: date }
- name: model
in: query
required: false
description: |
AI model to scope to. Accepts a Semrush Elements model name directly, or a
SpaceCat/UI platform code (translated server-side). Defaults to `search-gpt`.
schema: { type: string }
- name: platform
in: query
required: false
description: Legacy alias for `model`; `model` takes precedence when both are given.
schema: { type: string }
- name: region
in: query
required: false
description: |
UI region code (e.g. `US`) resolved server-side to a Semrush `project_id`.
`all` or omitted → across the brand's markets.
schema: { type: string }
- name: page
in: query
required: false
description: Zero-based page index. Defaults to 0.
schema: { type: integer, minimum: 0, default: 0 }
- name: pageSize
in: query
required: false
description: Page size (1..1000). Defaults to 50.
schema: { type: integer, minimum: 1, maximum: 1000, default: 50 }
responses:
'200':
description: Topic prompts retrieved.
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityBrandPresenceTopicPrompts' }
'400': { $ref: './responses.yaml#/400' }
'403':
description: Caller lacks access to the organization.
'404':
description: Organization not found, brand not found for this organization, the brand has no Semrush sub-workspace, or no Semrush market resolves for the requested region.
'502':
description: Upstream returned a non-2xx response.
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityErrorResponse' }
'503':
description: PostgREST client not available (required to resolve the brand's Semrush workspace before the element call).
content:
application/json:
schema: { $ref: './schemas.yaml#/SerenityErrorResponse' }
'500': { $ref: './responses.yaml#/500' }

v2-serenity-brand-presence-stats:
parameters:
- name: spaceCatId
Expand Down
Loading
Loading