Sources
The Sources API returns the AI-cited domains and URLs analyzed throughout a project. It is part of citation analysis of SE Visible where prompts and AI results tell you what AI engines said, and sources tell you which web pages they pulled the information from. Use it to identify the domains and pages that drive your AI visibility, see how often they appear in AI answers, and track whether they mention your brand or your competitors’ brands.
Using the SE Visible API, you can:
- list the domains (or subdomains) AI models cite for a project, with appearance counts, coverage, prompt reach, and domain trust, backlink, and traffic data
- drill into the individual URLs behind those domains, with page title, category, HTTP status, traffic, and backlink type
- filter sources by model, location, topic, prompt, sentiment, brand mentions, competitor presence, backlink type, and domain type
- compare a selected metric across two different date ranges to analyze performance changes
- get aggregated source metrics grouped by domain, URL, page type, domain type, AI model, or check date for tables and charts
All endpoints are relative to the base URL https://api.seranking.com/v1/se-visible.
Get project sources
GET https://api.seranking.com/v1/se-visible/projects/{project_id}/sources
Retrieves the sources (domains, subdomains, or URLs) that AI models cited across a project, with extensive filtering. The shape of each row in the response depends on source_type: domain returns one row per registrable domain (its subdomains are aggregated into the row), subdomain returns one row per host exactly as collected, and url returns one row per cited page.
Note:
source_typeswitches the response between domain rows (domainandsubdomain) and URL rows. It also changes whichsource_sort_fieldandcolumnsvalues are valid: passing a value that belongs to the other type returns422.- Most numeric fields are wrapped in a metric object with a
valuesarray. A single period returns one entry invalues. When you supplydate_range[1](compare mode), the field returns two entries plus adeltawithabsoluteandpercentage.
Request parameters
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | String (UUID) | Yes | UUID of the project. |
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| date_range | Array of Object | Yes | N/A | 1 to 2 entries: base period at index 0, optional compare period at index 1. Each has from and to in YYYY-MM-DD. See Date ranges and compare mode. |
| source_type | String | No | domain | Row shape of the response: domain (one row per registrable domain, subdomains aggregated into it), subdomain (one row per host as collected), or url (one row per page). Also determines the valid set of source_sort_field and columns values. |
| model_types | Array of String | No | N/A | Filter by AI model types (e.g. chatgpt). |
| country_codes | Array of String | No | N/A | Deprecated — use location_ids. Filter by ISO 3166-1 alpha-2 country codes. Resolved to the project’s live locations in those countries, so a deleted location is not matched, a country the project no longer tracks returns an empty result, and two locations in one country cannot be told apart. It keeps working for now; migrate to location_ids before it is withdrawn. |
| location_ids | Array of String (UUID) | No | N/A | Filter by the project’s tracked locations, using location IDs from List project locations. Multiple values combine as OR. An ID from another project or of a deleted location returns 422. Combined with country_codes, only locations matching both are read. A row is attributed to the location its check collected it under, so a location added later has no earlier history. |
| topic_ids | Array of Integer | No | N/A | Filter by topic IDs. |
| prompt_ids | Array of Integer | No | N/A | Filter by prompt IDs. |
| req_num | Integer | No | N/A | Limit to the answers with this request number within a check. |
| sentiments | Array of String | No | N/A | Filter by sentiment: positive, neutral, negative. |
| exclude_branded | Boolean | No | N/A | When true, every number in the response is computed from non-branded prompts only, and branded prompts drop out. A prompt not yet classified counts as non-branded. Off when omitted. |
| search_query | String | No | N/A | Filter sources by a substring of the domain or URL. |
| domain_id | Integer | No | N/A | Restrict results to a single domain. |
| types | Array of String | No | N/A | Filter by URL category type (e.g. blog, news, social). See the Reference for the full list. |
| is_my_brand_mentions | Integer | No | N/A | Filter sources by whether the project’s primary brand is mentioned: 1 mentioned, 0 not mentioned, -1 mention status not available. |
| has_backlink | Array of String | No | N/A | Filter source pages by backlink_type: dofollow (links to a brand domain and passes authority), nofollow (links to a brand domain without passing authority), none (checked, no link to a brand domain). Several values combine as OR. Pages not yet checked or that could not be read match none of the values; -1 is not accepted. URL rows only: with source_type=domain (the default) it returns 422. |
| competitors_count_from | Integer | No | N/A | Minimum number of competitor brands on the source (inclusive, min 0). |
| competitors_count_to | Integer | No | N/A | Maximum number of competitor brands on the source (inclusive, min 0). |
| brand_ids | Array of Integer | No | N/A | Keep sources that mention these brand IDs (see brand_match_mode). |
| brand_match_mode | String | No | any | When filtering by brand_ids, match any of the brands or all of them. |
| domain_types | Array of String | No | N/A | Filter rows by their domain type; several values combine as OR. Matches any element of the row’s domain_type array. Values: you (the primary brand’s own domain), competitors (a domain of another tracked brand), corporate, ugc, editorial, reference, institutional (stored base classification), other (neither a role nor a classification). domain and subdomain rows only: with source_type=url it returns 422. |
| columns | Array of String | No | All columns | Column ids to return. When omitted, every column is returned. When provided, each row contains only these columns plus the always-present locked first column (domain or url), domain_id, which is used to drill down from a domain row to its URLs, and url_id on URL rows. Key order in the response is not guaranteed. The valid set depends on source_type; see the note below. |
| source_sort_field | String | No | ai_answers_count | Field to sort by. The valid set depends on source_type; see the note below. |
| sort_order | String | No | desc | Sort direction: asc or desc. |
| limit | Integer | No | 1000 | Maximum number of sources to return (min 0). 0 returns every row and ignores offset. |
| offset | Integer | No | 0 | Number of sources to skip from the start of the list (min 0). |
Valid source_sort_field values
source_type=domainandsource_type=subdomain—ai_answers_count,pages,coverage,prompts_count,mention_rate,my_brand_mentions_count,competitors_count,first_seen,last_seen,dt,backlinks,referring_domains,domain_traffic, and the delta variantsai_answers_count_delta,pages_delta,coverage_delta,prompts_count_delta,mention_rate_delta,my_brand_mentions_count_delta,competitors_count_delta,responses_count_delta.source_type=url—ai_answers_count,coverage,prompts_count,competitors_count,my_brand_mentions,gap_score,first_seen,last_seen,last_check_date,dt,traffic,domain_traffic, and the delta variantsai_answers_count_delta,prompts_count_delta,coverage_delta,responses_count_delta.- The delta variants sort by the absolute change between periods (period 0 minus period 1) and require
date_range[1], otherwise the request is rejected with422. Rows with anulldelta — for example when a strict-null metric such ascoverageis missing in one period — are pushed to the end of the result in both ascending and descending order. - Rows with no value for
dt,traffic,domain_traffic,backlinks,referring_domains,gap_score,first_seen,last_seen, orlast_check_datealso go to the end in both directions. Period metrics computed per request, such ascoverage, keep the default order: nulls first ascending, last descending.
Valid columns ids
source_type=domain—domain,domain_type,subdomains_count,pages,coverage,ai_answers_count,prompts_count,my_brand_mentions_count,mention_rate,brand_ids,domain_traffic,dt,backlinks,referring_domains,first_seen,last_seen,competitors_count,responses_count.source_type=subdomain— same asdomain, minussubdomains_count.source_type=url—url,title,type,coverage,ai_answers_count,prompts_count,my_brand_mentions,gap_score,brand_ids,domain_traffic,dt,traffic,backlink_type,last_check_date,first_seen,last_seen,status,competitors_count,responses_count.- The locked column (
domainorurl) is accepted but redundant — it is always returned regardless of the requested ids. An id outside the set allowed for the currentsource_typereturns422.
Note: tracked_brand_ids is no longer part of this endpoint’s contract. It was previously accepted but never applied, so removing it changes no response. If your integration passed it here, the data you received was unfiltered — please re-check it. To filter sources by brand, use brand_ids together with brand_match_mode.
Request example
curl -X GET --globoff 'https://api.seranking.com/v1/se-visible/projects/550e8400-e29b-41d4-a716-446655440000/sources?source_type=domain&date_range[0][from]=2026-05-01&date_range[0][to]=2026-05-31&source_sort_field=ai_answers_count&sort_order=desc' \
-H 'Authorization: Token YOUR_API_KEY'To return only selected columns, pass columns[]:
curl -X GET --globoff 'https://api.seranking.com/v1/se-visible/projects/550e8400-e29b-41d4-a716-446655440000/sources?source_type=url&date_range[0][from]=2026-05-01&date_range[0][to]=2026-05-31&columns[]=title&columns[]=coverage&columns[]=ai_answers_count' \
-H 'Authorization: Token YOUR_API_KEY'Response parameters
If successful, the server returns a sources object with the row list and a total count.
| Parameter | Type | Description |
|---|---|---|
| items | Array | Source rows. Each row is a domain object (when source_type=domain) or a URL object (when source_type=url). |
| total | Integer | Total number of sources available for the filters. |
Most numeric fields are returned as a metric object rather than a plain number:
| Field | Type | Description |
|---|---|---|
| values | Array of Number | Metric value per period. One entry for a single period; two entries in compare mode (base, then compare). An entry can be null when a period has no data. |
| delta | Object | Present only in compare mode. Difference between the two periods. |
| delta.absolute | Number or null | Absolute change (base minus compare). null when a period has no data. |
| delta.percentage | Number or null | Percentage change. null when a period has no data. |
Domain rows (source_type=domain or source_type=subdomain)
| Parameter | Type | Description |
|---|---|---|
| domain | String | Domain name: the registrable domain for source_type=domain, the host exactly as collected for source_type=subdomain. |
| domain_id | Integer | Unique domain identifier. |
| domain_type | Array of String | The row’s domain types (1 or 2 values): the project role first — you for the primary brand’s own domain, otherwise competitors for a domain owned by another tracked brand — then the stored base classification (corporate, ugc, editorial, reference, institutional). ["other"] when the row has neither, so a competitor that is also an editorial site reads ["competitors", "editorial"]. |
| brand_ids | Array of Integer | Brand IDs mentioned on this domain. |
| first_seen | Datetime | First time this domain appeared in results. |
| last_seen | Datetime | Last time this domain appeared in results. |
| ai_answers_count | Metric object | Distinct answers in the period that cite at least one page of this source. |
| pages | Metric object | Distinct pages of this domain cited in the period’s answers. |
| subdomains_count | Metric object | Distinct subdomains of the domain that appeared as a source in the period. source_type=domain only; absent for subdomain rows. |
| coverage | Metric object | ai_answers_count as a percentage of responses_count, one decimal. null when responses_count is 0. |
| competitors_count | Metric object | Distinct competitor brands attached to this domain’s source URLs in the period. |
| prompts_count | Metric object | Distinct prompts whose answers cited this source in the period. |
| my_brand_mentions_count | Metric object | URLs on this domain that mention the primary brand. |
| mention_rate | Metric object | Percentage of this domain’s pages in the period whose content mentions the primary brand (my_brand_mentions_count / pages * 100), whole number. null in a period where the domain has no pages. |
| responses_count | Metric object | Answers in the period that name at least one brand, after the request’s filters. The same for every row; 0 in a period the source was not cited. |
| dt | Integer or null | Domain trust (0–100 inlink rank). Domain-level and project-agnostic, so a plain number rather than a metric object. A non-negative number is a measurement, -1 means the data source had nothing for this row, and null means it has not been requested yet. |
| backlinks | Integer or null | Total backlinks to the domain. Plain number; same null rule as dt. |
| referring_domains | Integer or null | Total referring domains. Plain number; same null rule as dt. |
| domain_traffic | Integer or null | Estimated monthly organic search traffic of the whole domain. Plain number; -1 when no data is available, null when not requested yet. |
URL rows (source_type=url)
| Parameter | Type | Description |
|---|---|---|
| url | String | Full URL. |
| url_id | Integer | URL identifier. Always returned, like domain_id. |
| domain_id | Integer | Identifier of the domain this URL belongs to. |
| brand_ids | Array of Integer or null | Brand IDs mentioned on this URL. An empty list means the page was read and no tracked brand matched. -1 means the page could not be read; null means it has not been parsed yet. Always consistent with my_brand_mentions. |
| title | String | Page title extracted from the HTML. |
| type | String | URL category type (e.g. blog, news, social). See the Reference for the full list. |
| status | Integer or null | HTTP status code of the URL. null if not yet checked. |
| first_seen | Datetime | First time this URL appeared in results. |
| last_seen | Datetime | Last time this URL appeared in results. |
| last_check_date | Datetime or null | When this URL was last parsed for brand mentions. null if not yet parsed. |
| competitors_count | Integer | Competitor brand count for this URL. Project-scoped rather than period-scoped, so it is a plain number rather than a metric object. my_brand_mentions and gap_score behave the same way. |
| my_brand_mentions | Integer or null | 1 if the URL currently mentions the primary brand, 0 if the page was read and the primary brand was not found, -1 if the page could not be read, null if not parsed yet. |
| gap_score | Integer or null | Gap score for ranking: base-period ai_answers_count times the number of tracked brands found on the page, so a page citing competitors in many answers scores high. 0 when the page mentions the primary brand, -1 when no tracked brand was found on the page or the page could not be read; null while the page is waiting for its first parse. |
| ai_answers_count | Metric object | Distinct answers in the period that cite at least one page of this source. |
| coverage | Metric object | ai_answers_count as a percentage of responses_count, one decimal. null when responses_count is 0. |
| prompts_count | Metric object | Distinct prompts whose answers cited this source in the period. |
| responses_count | Metric object | Answers in the period that name at least one brand, after the request’s filters. The same for every row; 0 in a period the source was not cited. |
| dt | Integer or null | Domain trust (0–100 inlink rank) of the URL’s domain. Plain number. A non-negative number is a measurement, -1 means the data source had nothing for this row, and null means it has not been requested yet. |
| traffic | Integer or null | Estimated monthly organic search traffic of this page, worldwide (not scoped to a search region). Plain number; -1 when no data is available, null when not requested yet. |
| domain_traffic | Integer or null | Estimated monthly organic search traffic of the page’s whole domain — the same value the domain row shows, distinct from traffic. Same -1 and null rules as traffic. |
| backlink_type | String or null | Whether this URL links to a domain of a tracked brand: dofollow (the link passes authority), nofollow (it does not), none (checked, no link to a brand domain), -1 (a parse was attempted and no link type was determined), null (not parsed yet). |
Response example
Domain sources, single period
{
"items": [
{
"domain": "example.com",
"domain_id": 123,
"ai_answers_count": {
"values": [45]
},
"pages": {
"values": [12]
},
"coverage": {
"values": [75.5]
},
"brand_ids": [1, 2],
"competitors_count": {
"values": [2]
},
"prompts_count": {
"values": [10]
},
"my_brand_mentions_count": {
"values": [3]
},
"mention_rate": {
"values": [25]
},
"responses_count": {
"values": [60]
},
"first_seen": "2024-01-01 00:00:00",
"last_seen": "2024-01-15 00:00:00",
"domain_type": ["competitors", "editorial"],
"subdomains_count": {
"values": [2]
},
"dt": 62,
"backlinks": 1520,
"referring_domains": 84,
"domain_traffic": 41000
}
],
"total": 1
}URL sources, compare mode
{
"items": [
{
"url": "https://example.com/article1",
"url_id": 4567,
"domain_id": 123,
"ai_answers_count": {
"values": [15, 8],
"delta": {
"absolute": 7,
"percentage": 87.5
}
},
"coverage": {
"values": [25.5, 16],
"delta": {
"absolute": 9.5,
"percentage": 59.38
}
},
"type": "blog",
"title": "Article 1",
"brand_ids": [1, 2],
"competitors_count": 2,
"my_brand_mentions": 1,
"gap_score": null,
"prompts_count": {
"values": [5, 3],
"delta": {
"absolute": 2,
"percentage": 66.67
}
},
"responses_count": {
"values": [60, 50],
"delta": {
"absolute": 10,
"percentage": 20
}
},
"first_seen": "2024-01-01 00:00:00",
"last_seen": "2024-02-15 00:00:00",
"last_check_date": "2024-02-15 00:00:00",
"status": 200,
"dt": 62,
"backlink_type": "dofollow",
"domain_traffic": null,
"traffic": 4321
}
],
"total": 1
}Get aggregated source metrics
GET https://api.seranking.com/v1/se-visible/projects/{project_id}/sources/metrics
Returns aggregated source metrics for dynamic table and chart rendering — the sources equivalent of Get aggregated brand metrics. You choose how the data is grouped (dimensions[]) and which metrics to return (metrics[]).
Note:
- You pass 1 to 3 dimensions: at most one entity or type grain (
url,domain,subdomain,page_type,domain_type), optionallymodel_type(the AI engine of the citing answers) beside it, and optionally one date dimension —check_idorcheck_datefor one row per check,check_weekorcheck_monthfor one row per calendar period (its checks aggregated, labelled by the period start).model_typeon its own is also a grain. - With 1 dimension, each row holds that dimension’s own columns plus one metric object per requested metric.
- With 2 or 3 dimensions, the response is a pivot: every dimension but the last keys the rows (in request order), and the last one becomes the columns.
meta.columns.dynamiclists the remaining row dimension names, then the pivot column IDs, labelled bymeta.columns.labels. Each cell is an object mapping every requested metric to its metric object. - Pivot rows are gap-filled with
0cells: a date dimension returns every base check or period,model_typeevery engine the project runs; entities and types appear only when cited. A filled cell still carries theresponses_countof its scope.limitandoffsetpage the filled rows. - A pivot over an entity grain (
url,domain,subdomain) requiresurl_ids[]ordomain_ids[]and plots exactly those IDs — fetch the top rows first, then the pivot for those IDs. A pivot does not acceptfiltersorsort_field, and a date dimension covers a single period: either returns422. - A date dimension on its own returns, per check, the period’s distinct AI answers that carry at least one brand mention, as rows with a single
ai_answers_countcell. These are totals across all sources (per-source counts never sum to them, since one answer cites several sources). Onlyai_answers_countis supported there, andfiltersrequire a grain. - Every metric value is an object, not a plain number:
{ "values": [v0] }in single-period mode. Passingdate_range[1]enables compare mode (requests without a date dimension only), which adds the second period and adeltaobject:{ "values": [v0, v1], "delta": { "absolute": 15, "percentage": 50 } }. Deltas are returned only in compare mode. subdomains_countis valid only when the grain isdomain, the only grain that folds subdomains into a domain row. With any other grain it returns422.
Request parameters
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | String (UUID) | Yes | UUID of the project. |
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| dimensions[] | Array of String | Yes | N/A | 1 to 3 dimensions, no duplicates. Two or more pivot by the last one, in request order. Values: check_id, check_date, check_week, check_month, url, domain, subdomain, page_type, domain_type, model_type. |
| week_start | Integer | No | 1 | First weekday for a check_week dimension, from 0 to 6 (0 Sunday, 6 Saturday). |
| metrics[] | Array of String | Yes | N/A | At least one metric, each returned as a metric object. Values: ai_answers_count, citations_share, prompts_count, my_brand_mentions_count, competitors_count, responses_count, subdomains_count. responses_count is the number of answers in the row’s scope (its period or check, and its engine under a model_type split) that carry at least one brand mention, cited or not — the citations_share denominator. It is the same for every entity or type in that scope and is not additive across them. |
| date_range | Array of Object | Yes | N/A | 1 to 2 entries: base period at index 0, optional compare period at index 1. Each has from and to in YYYY-MM-DD. Each period aggregates all checks within its dates. See Date ranges and compare mode. |
| model_types | Array of String | No | N/A | Filter by AI model types (e.g. chatgpt). |
| country_codes | Array of String | No | N/A | Deprecated — use location_ids. Filter by ISO 3166-1 alpha-2 country codes. Resolved to the project’s live locations in those countries, so a deleted location is not matched, a country the project no longer tracks returns an empty result, and two locations in one country cannot be told apart. It keeps working for now; migrate to location_ids before it is withdrawn. |
| location_ids | Array of String (UUID) | No | N/A | Filter by the project’s tracked locations, using location IDs from List project locations. Multiple values combine as OR. An ID from another project or of a deleted location returns 422. Combined with country_codes, only locations matching both are read. |
| topic_ids | Array of Integer | No | N/A | Filter by topic IDs. |
| sentiments | Array of String | No | N/A | Filter by sentiment: positive, neutral, negative. |
| exclude_branded | Boolean | No | N/A | When true, every number in the response is computed from non-branded prompts only. A prompt not yet classified counts as non-branded. Off when omitted. |
| prompt_ids | Array of Integer | No | N/A | Filter by prompt IDs. |
| req_num | Integer | No | N/A | Limit to the answers with this request number within a check. |
| search_query | String | No | N/A | Search query for filtering results. |
| filters | Array of Object | No | N/A | Up to 10 post-aggregation metric conditions, combined with AND. Rows failing any condition are dropped, and meta.pagination.total reflects that. Each condition has metric (a metrics[] value), target (0 base period value, 1 compare period value, or delta absolute change; 1 and delta require date_range[1]), operator (gt, gte, eq, lt, lte), and value (a number). All four are required. Example: filters[0][metric]=ai_answers_count&filters[0][target]=delta&filters[0][operator]=gt&filters[0][value]=0. |
| url_ids[] | Array of Integer | No | N/A | Up to 50 IDs. Narrow the sources the rows aggregate to these url_id values, whatever the grain. Required for a pivot over an entity grain, which plots exactly these IDs. |
| domain_ids[] | Array of Integer | No | N/A | Up to 50 IDs. Narrow the sources to these domain_id values (as returned in the rows), whatever the grain. In the subdomain grain an ID selects exactly that subdomain; in the other grains a domain ID also matches every URL and subdomain under it. |
| types[] | Array of String | No | N/A | Up to 50 values. Narrow the sources to these page types (e.g. listicle, blog, news), whatever the grain. See the Reference for the full list. |
| domain_types[] | Array of String | No | N/A | Up to 50 values. Narrow the sources to these domain types (matches any element of a row’s domain_type array), whatever the grain: you, competitors, corporate, ugc, editorial, reference, institutional, other. |
| sort_field | String | No | First metric, descending | A requested metric name; sorts on period 0 values. Append _delta to sort by the absolute delta (e.g. ai_answers_count_delta), which requires date_range[1], otherwise the request returns 422. |
| sort_order | String | No | desc | Sort direction: asc or desc. |
| limit | Integer | No | 50 | Maximum rows to return, from 0 to 1000. 0 returns every row and requires two or more dimensions (422 otherwise). |
| offset | Integer | No | 0 | Number of rows to skip (min 0). |
Request example
curl -X GET --globoff 'https://api.seranking.com/v1/se-visible/projects/550e8400-e29b-41d4-a716-446655440000/sources/metrics?dimensions[]=domain&metrics[]=ai_answers_count&metrics[]=citations_share&date_range[0][from]=2026-05-01&date_range[0][to]=2026-05-31' \
-H 'Authorization: Token YOUR_API_KEY'To chart selected domains per check date, pivot by domain and pass the domain IDs:
curl -X GET --globoff 'https://api.seranking.com/v1/se-visible/projects/550e8400-e29b-41d4-a716-446655440000/sources/metrics?dimensions[]=check_date&dimensions[]=domain&domain_ids[]=123&domain_ids[]=456&metrics[]=ai_answers_count&metrics[]=citations_share&date_range[0][from]=2026-01-01&date_range[0][to]=2026-01-31' \
-H 'Authorization: Token YOUR_API_KEY'Response parameters
If successful, the server returns a metrics object with pagination, column layout, and the data rows.
| Parameter | Type | Description |
|---|---|---|
| meta | Object | Pagination and column layout. |
| meta.pagination.total | Integer | Total rows: the grain values, or the filled rows of a pivot. |
| meta.columns.primary | String | First dimension the rows are keyed by (one of the dimensions[] values). |
| meta.columns.dynamic | Array of String | With 1 dimension, the requested metric names. In a pivot, the remaining row dimension names, then the pivot column IDs (entity IDs, type values, or date labels, as strings). |
| meta.columns.labels | Object | Pivot only. Maps each pivot column ID to its display label (URL or domain name, or the value itself). |
| data | Array | Rows. With 1 dimension, each row is keyed by its own columns — domain_id and domain for the domain and subdomain grains; url_id, url, and domain_id for url; page_type, domain_type, or model_type for the type grains; the date label for a date dimension — plus one metric object per requested metric. In a pivot, each row holds the row dimensions’ columns, then one cell per pivot column keyed by its ID, mapping every requested metric to its metric object, with 0 cells where nothing was cited. |
Response example
Domain grain, single period
{
"meta": {
"pagination": { "total": 2 },
"columns": { "primary": "domain", "dynamic": ["ai_answers_count", "citations_share"] }
},
"data": [
{
"domain_id": 123,
"domain": "example.com",
"ai_answers_count": { "values": [45] },
"citations_share": { "values": [75] }
},
{
"domain_id": 456,
"domain": "other.com",
"ai_answers_count": { "values": [27] },
"citations_share": { "values": [45] }
}
]
}Domain grain, compare mode
{
"meta": {
"pagination": { "total": 1 },
"columns": { "primary": "domain", "dynamic": ["ai_answers_count"] }
},
"data": [
{
"domain_id": 123,
"domain": "example.com",
"ai_answers_count": {
"values": [45, 30],
"delta": { "absolute": 15, "percentage": 50 }
}
}
]
}Pivot: check date by domain, gap-filled
{
"meta": {
"pagination": { "total": 2 },
"columns": {
"primary": "check_date",
"dynamic": ["123", "456"],
"labels": { "123": "example.com", "456": "other.com" }
}
},
"data": [
{
"check_date": "2026-01-01",
"123": {
"ai_answers_count": { "values": [45] },
"citations_share": { "values": [12.5] }
},
"456": {
"ai_answers_count": { "values": [0] },
"citations_share": { "values": [0] }
}
},
{
"check_date": "2026-01-08",
"123": {
"ai_answers_count": { "values": [41] },
"citations_share": { "values": [11.9] }
},
"456": {
"ai_answers_count": { "values": [3] },
"citations_share": { "values": [0.9] }
}
}
]
}
