Skip to Content
APIEndpointsTopic scoreboard

Topic scoreboard

Every topic and subtopic in one call, each with its visibility, its change against the prior window, the leading competitor, the gap to them, and how much open work it carries.

This is the closest thing on the surface to a to-do list: it answers “which topics need attention” without you first knowing which topics to ask about.

GET /v1/brands/{brand_id}/topics/scoreboard

Authorization

HeaderTypeRequired
AuthorizationBearer asky_sk_…required

Path parameters

ParameterTypeRequiredDescription
brand_iduuidrequiredFrom List brands

Query parameters

ParameterTypeRequiredDescription
limitintegeroptionalRows per page, 1 to 100. Defaults to 20.
cursorstringoptionalOpaque cursor from the previous response. Treat it as a token, never construct one.
window_daysintegeroptionalLookback window in days.

Request

curl --request GET \ --url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/topics/scoreboard?window_days=28' \ --header 'Authorization: Bearer <api-key>'

Response

{ "data": [ { "topic_id": "4beb0694-7c2e-488b-84c1-613738e7eaf6", "topic_name": "AI Visibility Tracking", "parent_topic_id": null, "is_subtopic": false, "visibility_pct": 41.2, "previous_visibility_pct": 36.8, "visibility_delta_pts": 4.4, "top_competitor_name": "Peec AI", "top_competitor_visibility_pct": 33.1, "gap_pts": -8.1, "our_rank": 1, "max_rank": 7, "prompt_count": 34, "citation_count": 128, "open_content_actions": 2, "open_task_count": 1, "has_enough_data": true } ], "pagination": { "limit": 20, "has_more": true, "next_cursor": "eyJ2IjoxLCJvIjoyMCwibCI6MjB9" }, "meta": { "window": { "days": 28, "start_date": "2026-07-16" } }, "request_id": "req_38b7ea15c9024fd0a6e3" }

Response fields

FieldTypeDescription
data.windowobjectrequired. { days, start_date }
data.topicsobject[]required
data.topics[].topic_iduuidrequired
data.topics[].topic_namestringrequired
data.topics[].parent_topic_iduuid | null
data.topics[].is_subtopicbooleanrequired
data.topics[].visibility_pctnumber | null
data.topics[].previous_visibility_pctnumber | null
data.topics[].visibility_delta_ptsnumber | nullChange in percentage points
data.topics[].top_competitor_namestring | nullWhoever leads this topic
data.topics[].top_competitor_visibility_pctnumber | null
data.topics[].gap_ptsnumber | nullSigned. Positive means they are ahead, negative means you lead
data.topics[].our_rankinteger | null
data.topics[].max_rankinteger | nullHow many entities are ranked on this topic
data.topics[].prompt_countintegerrequired
data.topics[].citation_countintegerrequired
data.topics[].open_content_actionsintegerrequired
data.topics[].open_task_countintegerrequired
data.topics[].has_enough_databooleanrequired. See the note below
data.countintegerrequired
request_idstringrequired. Also returned as the x-request-id header. Quote it when contacting support

Errors

StatusCodeWhen
400invalid_requestA parameter is unknown or malformed. The message names it
401invalid_tokenThe key is missing, malformed, or does not exist
401token_expiredThe key passed its expiry date
401token_revokedThe key was revoked
404not_foundThe brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable
429rate_limitedOver 300 requests per minute. See the Retry-After header

Notes

Filter on has_enough_data before ranking anything. It applies the product’s own eligibility floor — at least 2 prompts and 5 citations in the window. Thin topics produce wild percentages and will dominate any “worst topics” list if you let them.

gap_pts is signed the way it reads: positive means the leading competitor is ahead of you.

Not paginated. A brand carries at most a few dozen topics, and the whole tree is returned.

Last updated on