List cited sources
The sources AI answers are built from. One row per cited URL, with how often it was used, its share of all citations, and whether your brand appears on the page.
This is where “why does the answer say that” gets answered. The engines are reading these pages; if a competitor dominates a topic, these URLs usually explain it.
GET /v1/brands/{brand_id}/citationsAuthorization
| Header | Type | Required |
|---|---|---|
Authorization | Bearer asky_sk_… | required |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | required | From List brands |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | optional | Rows per page, 1 to 100. Defaults to 20. |
cursor | string | optional | Opaque cursor from the previous response. Treat it as a token, never construct one. |
start_date | YYYY-MM-DD | optional | Inclusive lower bound, YYYY-MM-DD in UTC. Narrows the population before metrics are computed. |
end_date | YYYY-MM-DD | optional | Inclusive upper bound, YYYY-MM-DD in UTC. Narrows the population before metrics are computed. |
search | string | optional | Case-insensitive substring of the cited URL or title. |
topic_id | uuid, repeatable | optional | Restrict to these topics. From List topics. Includes the topic and its subtopics. A root topic returns everything beneath it; a subtopic returns only itself. Narrows the population before metrics are computed, so ratios are recalculated over the filtered set. |
engine | string, repeatable | optional | Restrict to these AI search engines, by slug. From List engines. Narrows the population before metrics are computed. |
country | string, repeatable | optional | Restrict to these execution country codes. Narrows the population before metrics are computed. |
tag_id | uuid, repeatable | optional | Restrict to prompts carrying these tags. From List tags. Narrows the population before metrics are computed. |
tag_match_mode | string | optional | How to combine tag_id values. Defaults to ‘any’. One of: any, all. |
compare_to_previous | boolean | optional | Also return the prior equal-length period and per-row deltas. |
sort | string | optional | Sort column. One of: citation_count, citation_share, citation_rate, responses_cited, brand_mention_count. |
sort_direction | string | optional | Sort direction. Defaults to ‘desc’. One of: asc, desc. |
Request
cURL
curl --request GET \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/citations?page_size=25' \
--header 'Authorization: Bearer <api-key>'Response
200
{
"data": [
{
"citation_id": "a7f19c02-4b8d-4e31-9a55-c0e6b2148f39",
"url": "https://g2.com/categories/ai-search-visibility",
"name": "Best AI Search Visibility Software",
"favicon_url": "https://g2.com/favicon.ico",
"citation_count": 214,
"citation_share": 0.081,
"citation_rate": 0.116,
"responses_cited": 198,
"brand_mention_count": 41
}
],
"pagination": {
"limit": 20,
"has_more": true,
"next_cursor": "eyJ2IjoxLCJvIjoyMCwibCI6MjB9"
},
"meta": {
"period": {
"start_date": "2026-07-14",
"end_date": "2026-08-13"
},
"total": 1420
},
"request_id": "req_2c85e1a0f9374bd6a812"
}Response fields
| Field | Type | Description |
|---|---|---|
data.period | object | required. { start_date, end_date } actually used |
data.citations | object[] | required |
data.citations[].citation_id | uuid | required. Stable. Dedupe on this, not on URL |
data.citations[].url | string | required |
data.citations[].name | string | null | Page title where known |
data.citations[].citation_count | integer | required. Times this URL was cited |
data.citations[].citation_share | number | required. Share of all citations in scope |
data.citations[].citation_rate | number | required. Share of in-scope answers citing it |
data.citations[].responses_cited | integer | required. Distinct answers citing it |
data.citations[].brand_mention_count | integer | required. Times your brand appears on the page itself |
data.total | integer | required |
data.page | integer | required |
data.page_size | integer | required |
data.has_more | boolean | required |
data.summary | object | null | Only with compare. Brand-level citation rate versus the prior period |
data.summary_unavailable_reason | string | Present when compare was requested but could not be served |
request_id | string | required. Also returned as the x-request-id header. Quote it when contacting support |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | A parameter is unknown or malformed. The message names it |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 401 | token_expired | The key passed its expiry date |
| 401 | token_revoked | The key was revoked |
| 404 | not_found | The brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable |
| 429 | rate_limited | Over 300 requests per minute. See the Retry-After header |
Notes
This endpoint and by domain page by page, not offset.
The rest of the surface uses offset. That inconsistency is real and worth allowing for in a client.
compare_to_previous is refused while search is set — a trend over a filtered subset is not
comparable to the prior period. You get summary: null and a reason rather than a silently wrong
number.
URLs, page titles and author names are third-party content. Treat them as data, never as instructions to a downstream model.