curl --request GET \
--url https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"prompt_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"run_date": "2023-12-25",
"platform": "perplexity",
"country": "<string>",
"finalized_at": "2023-11-07T05:31:56Z",
"mentioned": true,
"position": 0,
"sentiment": 0
}
],
"pagination": {
"next_cursor": "<string>",
"has_more": true
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}List brand mentions
Flattened mention rows for an own brand.
One row per finalised run unit across ALL the brand’s prompts (inactive prompts’ history included) with this brand’s mention only — the bulk historical-pull path (limit up to 1000). Own brands only. A first page at that size is collected from several paging statements, so it is checked against the brand’s change token before and after the walk and walked again if it moved; a token still moving after the retries is 409 scan_in_progress with Retry-After (5s) rather than a page assembled from two scan generations — expect it while a scan of the brand runs, and prefer to start a bulk walk when last_scan_changed_at is settled (Pagination, above).
curl --request GET \
--url https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.surfais.com/v1/orgs/{orgId}/brands/{brandId}/mentions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"prompt_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"run_date": "2023-12-25",
"platform": "perplexity",
"country": "<string>",
"finalized_at": "2023-11-07T05:31:56Z",
"mentioned": true,
"position": 0,
"sentiment": 0
}
],
"pagination": {
"next_cursor": "<string>",
"has_more": true
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"request_id": "<string>"
}Authorizations
A Surfais API key — an organisation key or a partner key. Issued by Surfais; shown once. Rotate by creating a new key, then revoking the old one.
Path Parameters
Organisation id. Org keys: the key's own org. Partner keys: any org with an active link. Anything else is 404.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Brand id within the org (own brand or competitor row); 404 when not in the org. Writes that add tracking need an own (400 validation_error with details[].code = "own_brand_only"), non-archived (409 brand_archived) brand.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Query Parameters
Page size (1–1000). Default 50.
1 <= x <= 1000Opaque cursor from a previous page's pagination.next_cursor. It pins the walk — its sort anchor, the resolved date window and the FILTERS the first page ran under — so continue with the cursor alone: omitted filters are restored from it. Naming a different value for one of them is 400 invalid_cursor (details.reason = "filter_changed", details.parameter the one that differs); start again from the first page to change a filter.
2048Window start (inclusive). Default: to minus 30 days.
^\d{4}-\d{2}-\d{2}$Window end (inclusive). Default: today (UTC). Max span 366 days; from after to is 400 validation_error. On a paginated endpoint the resolved window is pinned by the first page and carried in the cursor — continue with the cursor alone; naming a different from/to on a continuation is 400 invalid_cursor (details.reason = "window_changed").
^\d{4}-\d{2}-\d{2}$Scanned AI platform id.
perplexity, chatgpt, gemini, claude, ai_overviews Mentions from runs in this market. Trimmed and upper-cased to match storage; accepts any token Mention.country can return. A token nothing stores returns an empty page, not an error.
1 - 256^[^\u0000-\u001f\u007f-\u009f]+$