AI Sources
REST endpoints for AI Sources. Base URL https://api.competlab.com; every request needs a CL-API-Key header (see Authentication). Responses wrap in { item } or { items }; errors in { error }.
Get latest AI sources data
/v1/projects/{projectId}/ai-sourcesGet the latest AI Sources data for a project: for each engine we ask — Perplexity and Google AI Overviews — which companies it named in answer to the project’s 8 buying questions, which pages it RETRIEVED to answer, and which of the pages more than one engine retrieved name the customer’s competitors and not the customer. Every number is read off the stored summary of the latest published check, the same document the app shows. Two sentences this data cannot support, and no field here claims: a CITATION count — an engine hands back the pages it retrieved while answering and does not say which it leaned on — and a POOLED page number — the engines read different pages, so page counts are per engine and are never added together. The one cross-engine object is the core, the hosts at least 2 engines retrieved (summary.overlap, summary.coreHosts); answers may pool as a vote on the leaderboard (summary.brands), and every such row says which engines back it. Counts are counts, never rates: report figures as n of N answers and never as a percentage or a share — the question set is small by design, and a share computed from it is false precision. Every count names its universe on the same object. An engine the check did not ask is ABSENT from every per-engine record, and absent means not measured, never zero; an engine present with engineDataAvailable produced nothing usable and carries no count. The question matrix has three cell states, never two: answered, no_answer_shown (the engine was read and showed nothing — measured, not an answer, not a failure) and not_measured (we could not read it — not a zero). A page we could not read is listed under its host with its reason and is never counted as a page the customer is absent from; only a core host whose status is missing supports ‘get onto this page’. actionHint.text on each core host and the sentences under summary.limits.sentences are payload: render them verbatim. Set includeAnswers=true to also get the engines’ raw answers on that check — the answer text, the companies read out of it in order of first mention, and the pages each engine retrieved with the passage it handed back — narrowed by engine= or promptIndex=. The block is large; the prose in it is the engine’s, not CompetLab’s. No filter changes a number under summary. When the most recent check was abandoned because no engine produced a usable answer, latestCheckDataAvailable is present and everything else describes an earlier check. A project with no published check yet answers 404 no_data_available — not a missing project and not a failed measurement, just nothing measured here so far; the project itself is fine and get_project still describes it. Distinguish it from project_not_found, which means the id is wrong.
Path parameters
| Name | Type | Description |
|---|---|---|
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
includeAnswers | boolean | Set true to include what the engines actually said — every question sent, the answer text, the companies read out of it in order of first mention, and the pages the engine RETRIEVED to write it, with the passage it handed back for each. Off by default because the block is large: up to 8 answers per engine, each carrying the engine’s full retrieved page list, which for a searching engine can run to dozens of pages with a passage each. Narrow with engine= or promptIndex= rather than fetching everything. The answer text is the engine’s wording, not CompetLab’s assessment; the pages are retrieved, never cited. Default false. | |
engine | string | Return only this engine’s answers. Requires includeAnswers=true. Narrows answers, unansweredQueries and noAnswerShown; changes nothing under summary and does not narrow engineStatus. Values: perplexity, google_ai_overviews. | |
promptIndex | number | Return only the answers for this question, across every engine. Requires includeAnswers=true. Zero-based: the question’s position in the check’s question list, matching promptIndex on each answer. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/ai-sources?includeAnswers=false&engine=perplexity&promptIndex=0" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"item": {
"lastUpdatedAt": "2026-09-04T10:00:00.000Z",
"summary": {
"customerDomain": "mycompany.com",
"verdict": "missing_from_most_core_hosts",
"window": {
"checkIds": [
"507f1f77bcf86cd799439012",
"507f1f77bcf86cd799439011"
],
"since": "2026-08-01T10:00:00.000Z",
"perEngine": {
"perplexity": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
},
"google_ai_overviews": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
}
}
},
"perEngine": {
"perplexity": {
"engineDataAvailable": {
"available": false,
"reason": "no_usable_answer"
},
"answersAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0,
"answersWithoutRetrieval": 1,
"answersNamingCustomer": 3,
"answersRetrievingOwnPage": 4,
"pagesRetrieved": 131,
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33,
"engineCoreSize": 35,
"pagesRead": 118,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"ownPagesRetrieved": 6,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
},
"topHosts": [
{
"host": "g2.com",
"pages": 3,
"promptIds": [],
"alsoRetrievedBy": [
"google_ai_overviews"
]
}
]
},
"google_ai_overviews": {
"engineDataAvailable": {
"available": false,
"reason": "no_usable_answer"
},
"answersAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0,
"answersWithoutRetrieval": 1,
"answersNamingCustomer": 3,
"answersRetrievingOwnPage": 4,
"pagesRetrieved": 131,
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33,
"engineCoreSize": 35,
"pagesRead": 118,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"ownPagesRetrieved": 6,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
},
"topHosts": [
{
"host": "g2.com",
"pages": 3,
"promptIds": [],
"alsoRetrievedBy": [
"google_ai_overviews"
]
}
]
}
},
"matrix": [
{
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools are safe to use with a Google Workspace domain?",
"intent": "safety",
"cells": {
"perplexity": {
"state": "answered",
"reason": "no_ai_overview_shown",
"named": false,
"companiesNamed": 6,
"webSearch": {},
"pagesRetrieved": 14,
"pagesRead": 12,
"pagesUnreadable": 1,
"pagesNotFetched": 1,
"pagesNamingCustomer": {},
"ownPagesRetrieved": 1
},
"google_ai_overviews": {
"state": "answered",
"reason": "no_ai_overview_shown",
"named": false,
"companiesNamed": 6,
"webSearch": {},
"pagesRetrieved": 14,
"pagesRead": 12,
"pagesUnreadable": 1,
"pagesNotFetched": 1,
"pagesNamingCustomer": {},
"ownPagesRetrieved": 1
}
}
}
],
"brands": [
{
"domain": "competitor.com",
"name": "Competitor Inc",
"isOwn": false,
"origin": "tracked_competitor",
"ambiguous": false,
"rankByPresence": 2,
"answers": {
"answersNaming": 5,
"answersReceived": 16,
"presence": 31,
"presenceLow": 14,
"presenceHigh": 56
},
"answersRetrievingOwnSite": {
"answersNaming": 5,
"answersReceived": 16,
"presence": 31,
"presenceLow": 14,
"presenceHigh": 56
},
"enginesNaming": [
"perplexity"
],
"perEngine": {
"perplexity": {
"answers": {},
"independentPagesNaming": {},
"pagesRead": 118,
"ownPagesRetrieved": 2
},
"google_ai_overviews": {
"answers": {},
"independentPagesNaming": {},
"pagesRead": 118,
"ownPagesRetrieved": 2
}
}
}
],
"overlap": {
"hostsInCore": 25,
"perEngine": {
"perplexity": {
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33
},
"google_ai_overviews": {
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33
}
}
},
"funnel": {
"coreHosts": 25,
"alreadyNamingCustomer": 19,
"unreadable": 2,
"missing": 4,
"missingPublishers": 3,
"missingCompetitorOwned": 1
},
"coreHosts": [
{
"host": "g2.com",
"status": "missing",
"ownership": "third_party",
"ownedBy": "competitor.com",
"kind": "review_site",
"kindCheckedAt": "2026-09-04",
"actionHint": {
"code": "pitch_publisher",
"text": "Pitch an update to this page: it names your competitors and not you."
},
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [
"value"
],
"seenInChecks": {
"perplexity": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
},
"google_ai_overviews": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
}
},
"brandsNamed": [
"competitor.com"
],
"pages": [
{
"key": "g2.com/categories/email-warm-up",
"url": "https://www.g2.com/categories/email-warm-up",
"host": "g2.com",
"title": "Best Email Warm-Up Software",
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [],
"ownedBy": "competitor.com",
"readState": "read",
"unreadableReason": "bot_protection",
"fetchedAt": "2026-09-04T10:00:00.000Z",
"textSource": "body",
"namesCustomer": "not_named",
"brandsNamed": [
"competitor.com",
"rival.io"
],
"excerpt": "…the most reliable options this year are Competitor Inc and Rival…"
}
]
}
],
"ownPageRetrievals": [
{
"engine": "perplexity",
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"pages": [
{
"key": "mycompany.com/pricing",
"url": "https://mycompany.com/pricing",
"title": "Pricing — My Company"
}
],
"companiesNamed": [
"competitor.com",
"rival.io"
],
"namedCustomer": false
}
],
"pages": [
{
"key": "g2.com/categories/email-warm-up",
"url": "https://www.g2.com/categories/email-warm-up",
"host": "g2.com",
"title": "Best Email Warm-Up Software",
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [
"value"
],
"ownedBy": "competitor.com",
"readState": "read",
"unreadableReason": "bot_protection",
"fetchedAt": "2026-09-04T10:00:00.000Z",
"textSource": "body",
"namesCustomer": "not_named",
"brandsNamed": [
"competitor.com",
"rival.io"
],
"excerpt": "…the most reliable options this year are Competitor Inc and Rival…"
}
],
"limits": {
"pagesRetrieved": 153,
"pagesRead": 140,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"pagesTruncated": 3,
"unreadableByReason": {
"bot_protection": 5,
"host_blocked_recently": 2,
"text_too_short": 1,
"not_found_page": 0,
"consent_wall": 0,
"unreachable": 0,
"timeout": 1,
"fetch_failed": 0,
"unresolved": 0
},
"textSourceMix": {
"body": 140,
"snippet_only": 9,
"none": 4
},
"sentences": [
{
"code": "sources_retrieved_not_cited",
"text": "Retrieved, never cited: these are the pages the engine pulled back while answering; which of them it leaned on is not something the engines disclose."
}
]
}
},
"trackedDomains": [
"mycompany.com",
"competitor.com"
],
"latestCheckDataAvailable": {
"available": false,
"reason": "no_usable_answer_from_any_engine",
"enginesAsked": [
"perplexity",
"google_ai_overviews"
]
},
"answers": [
{
"engine": "perplexity",
"promptIndex": 0,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools are safe to use with a Google Workspace domain?",
"intent": "safety",
"askedIn": {
"locationName": "United States",
"languageName": "English"
},
"answerText": "For a Google Workspace domain, the safest warm-up tools are Competitor Inc and Rival, both of which…",
"companiesNamed": [
{
"rank": 1,
"name": "Competitor Inc",
"domain": "competitor.com"
}
],
"sources": [
{
"url": "https://www.g2.com/categories/email-warm-up",
"domain": "g2.com",
"title": "Best Email Warm-Up Software",
"snippet": "Warm-up tools gradually increase sending volume so that mailbox providers…",
"publishedAt": "2026-05-12",
"resolvedFrom": "https://www.google.com/goto?url=…"
}
],
"searchQueries": [
"email warm-up tools Google Workspace safe"
],
"webSearch": {
"performed": true,
"completedSearchCount": 3,
"reason": "NO_SEARCH_ATTEMPTED"
}
}
],
"unansweredQueries": [
{
"engine": "perplexity",
"promptIndex": 5,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools have a free plan?",
"reason": "no_usable_answer"
}
],
"noAnswerShown": [
{
"engine": "google_ai_overviews",
"promptIndex": 3,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools have a free plan?",
"reason": "no_ai_overview_shown"
}
],
"engineStatus": {
"perplexity": {
"reported": true,
"completedAt": "2026-09-04T10:00:00.000Z",
"questionsAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0
},
"google_ai_overviews": {
"reported": true,
"completedAt": "2026-09-04T10:00:00.000Z",
"questionsAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0
}
},
"answersTruncated": false
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_parameters · invalid_run_id · invalid_check_id | Bad request — the payload failed validation. |
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
| 404 | project_not_found · no_data_available | No project matches the id in the path. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "invalid_parameters",
"message": "Domain is required",
"status": 400
}
}Get AI sources check history
/v1/projects/{projectId}/ai-sources/historyGet paginated history of AI Sources checks for a project. Each row carries, per engine, the four measured figures for that check — answers received, answers naming the customer, pages read, and independent pages naming the customer — and the funnel from core hosts to hosts the customer is genuinely missing from. Nothing is summed across engines; an engine absent from a row was not asked on that check or produced nothing usable on it, and absent means not measured, never zero. Counts are counts, never rates: report figures as n of N answers and never as a percentage or a share — the question set is small by design, and a share computed from it is false precision. Only published checks are listed: a check abandoned because no engine produced a usable answer never publishes and does not appear here. Uses checkId, not runId — the unit of this dimension is a check, one cycle of every question against every engine. The full summary for a row is on the check-detail route. This page is subject to a response size cap: when truncated is true, whole entries were dropped from the end of items and pagination.hasMore does NOT account for them — lower limit to see the rest rather than paging forward, which would skip them.
Path parameters
| Name | Type | Description |
|---|---|---|
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | number | Page number (1-indexed). Default 1. Min 1. | |
limit | number | Number of items per page. Default 20. Range 1–100. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/ai-sources/history?page=1&limit=20" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"items": [
{
"checkId": "507f1f77bcf86cd799439012",
"completedAt": "2026-09-04T10:00:00.000Z",
"perEngine": {
"perplexity": {
"answersReceived": 7,
"answersNamingCustomer": 3,
"pagesRead": 118,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
}
},
"google_ai_overviews": {
"answersReceived": 7,
"answersNamingCustomer": 3,
"pagesRead": 118,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
}
}
},
"funnel": {
"coreHosts": 25,
"alreadyNamingCustomer": 19,
"unreadable": 2,
"missing": 4,
"missingPublishers": 3,
"missingCompetitorOwned": 1
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 47,
"totalPages": 3,
"hasMore": true
},
"truncated": false
}Paginated — pass page and limit query parameters and follow pagination.hasMore to page through the full set.
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "api_key_invalid",
"message": "Invalid API key",
"status": 401
}
}Get AI sources data for a specific check
/v1/projects/{projectId}/ai-sources/history/{checkId}Get full AI Sources data for a specific historical check: the summary stored on that check under summary, in exactly the dashboard’s shape and read the same way — per engine, never pooled; retrieved, never cited; only a missing core host is a page to get onto; actionHint.text and summary.limits.sentences are rendered verbatim. The window it pools over (up to 5 published checks, this one first) is on summary.window. Set includeAnswers=true to also get what the engines actually said: every question sent, the answer text, the companies read out of it in order of first mention, and the pages the engine retrieved with the passage it handed back for each — plus engineStatus, one entry per engine the check asked. That block is large; narrow with engine= (one engine) or promptIndex= (one question). No filter changes any number under summary; ranks are stable under filtering. Counts are counts, never rates: report figures as n of N answers and never as a percentage or a share — the question set is small by design, and a share computed from it is false precision. Questions we could not read are listed separately in unansweredQueries, and questions an engine was read for and showed no answer to in noAnswerShown — three different facts, and none of them is ‘not named’. A malformed id answers 400 invalid_check_id; an id that does not belong to this project answers 404 check_not_found; a check that exists but has no published summary — still running, or abandoned (no engine produced a usable answer, or the page stage could not be closed) — answers 404 run_not_summarized, which is a different fact from check_not_found: the check exists, it has nothing to report.
Path parameters
| Name | Type | Description |
|---|---|---|
checkId | string | Check ID |
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
includeAnswers | boolean | Set true to include what the engines actually said — every question sent, the answer text, the companies read out of it in order of first mention, and the pages the engine RETRIEVED to write it, with the passage it handed back for each. Off by default because the block is large: up to 8 answers per engine, each carrying the engine’s full retrieved page list, which for a searching engine can run to dozens of pages with a passage each. Narrow with engine= or promptIndex= rather than fetching everything. The answer text is the engine’s wording, not CompetLab’s assessment; the pages are retrieved, never cited. Default false. | |
engine | string | Return only this engine’s answers. Requires includeAnswers=true. Narrows answers, unansweredQueries and noAnswerShown; changes nothing under summary and does not narrow engineStatus. Values: perplexity, google_ai_overviews. | |
promptIndex | number | Return only the answers for this question, across every engine. Requires includeAnswers=true. Zero-based: the question’s position in the check’s question list, matching promptIndex on each answer. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/ai-sources/history/507f1f77bcf86cd799439012?includeAnswers=false&engine=perplexity&promptIndex=0" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"item": {
"checkId": "507f1f77bcf86cd799439012",
"completedAt": "2026-09-04T10:00:00.000Z",
"summary": {
"customerDomain": "mycompany.com",
"verdict": "missing_from_most_core_hosts",
"window": {
"checkIds": [
"507f1f77bcf86cd799439012",
"507f1f77bcf86cd799439011"
],
"since": "2026-08-01T10:00:00.000Z",
"perEngine": {
"perplexity": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
},
"google_ai_overviews": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
}
}
},
"perEngine": {
"perplexity": {
"engineDataAvailable": {
"available": false,
"reason": "no_usable_answer"
},
"answersAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0,
"answersWithoutRetrieval": 1,
"answersNamingCustomer": 3,
"answersRetrievingOwnPage": 4,
"pagesRetrieved": 131,
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33,
"engineCoreSize": 35,
"pagesRead": 118,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"ownPagesRetrieved": 6,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
},
"topHosts": [
{
"host": "g2.com",
"pages": 3,
"promptIds": [],
"alsoRetrievedBy": [
"google_ai_overviews"
]
}
]
},
"google_ai_overviews": {
"engineDataAvailable": {
"available": false,
"reason": "no_usable_answer"
},
"answersAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0,
"answersWithoutRetrieval": 1,
"answersNamingCustomer": 3,
"answersRetrievingOwnPage": 4,
"pagesRetrieved": 131,
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33,
"engineCoreSize": 35,
"pagesRead": 118,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"ownPagesRetrieved": 6,
"independentPagesNamingCustomer": {
"floor": 4,
"ceiling": 6
},
"topHosts": [
{
"host": "g2.com",
"pages": 3,
"promptIds": [],
"alsoRetrievedBy": [
"google_ai_overviews"
]
}
]
}
},
"matrix": [
{
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools are safe to use with a Google Workspace domain?",
"intent": "safety",
"cells": {
"perplexity": {
"state": "answered",
"reason": "no_ai_overview_shown",
"named": false,
"companiesNamed": 6,
"webSearch": {},
"pagesRetrieved": 14,
"pagesRead": 12,
"pagesUnreadable": 1,
"pagesNotFetched": 1,
"pagesNamingCustomer": {},
"ownPagesRetrieved": 1
},
"google_ai_overviews": {
"state": "answered",
"reason": "no_ai_overview_shown",
"named": false,
"companiesNamed": 6,
"webSearch": {},
"pagesRetrieved": 14,
"pagesRead": 12,
"pagesUnreadable": 1,
"pagesNotFetched": 1,
"pagesNamingCustomer": {},
"ownPagesRetrieved": 1
}
}
}
],
"brands": [
{
"domain": "competitor.com",
"name": "Competitor Inc",
"isOwn": false,
"origin": "tracked_competitor",
"ambiguous": false,
"rankByPresence": 2,
"answers": {
"answersNaming": 5,
"answersReceived": 16,
"presence": 31,
"presenceLow": 14,
"presenceHigh": 56
},
"answersRetrievingOwnSite": {
"answersNaming": 5,
"answersReceived": 16,
"presence": 31,
"presenceLow": 14,
"presenceHigh": 56
},
"enginesNaming": [
"perplexity"
],
"perEngine": {
"perplexity": {
"answers": {},
"independentPagesNaming": {},
"pagesRead": 118,
"ownPagesRetrieved": 2
},
"google_ai_overviews": {
"answers": {},
"independentPagesNaming": {},
"pagesRead": 118,
"ownPagesRetrieved": 2
}
}
}
],
"overlap": {
"hostsInCore": 25,
"perEngine": {
"perplexity": {
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33
},
"google_ai_overviews": {
"hostsRetrieved": 58,
"hostsOnlyThisEngine": 33
}
}
},
"funnel": {
"coreHosts": 25,
"alreadyNamingCustomer": 19,
"unreadable": 2,
"missing": 4,
"missingPublishers": 3,
"missingCompetitorOwned": 1
},
"coreHosts": [
{
"host": "g2.com",
"status": "missing",
"ownership": "third_party",
"ownedBy": "competitor.com",
"kind": "review_site",
"kindCheckedAt": "2026-09-04",
"actionHint": {
"code": "pitch_publisher",
"text": "Pitch an update to this page: it names your competitors and not you."
},
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [
"value"
],
"seenInChecks": {
"perplexity": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
},
"google_ai_overviews": {
"checkIds": [
"507f1f77bcf86cd799439012"
]
}
},
"brandsNamed": [
"competitor.com"
],
"pages": [
{
"key": "g2.com/categories/email-warm-up",
"url": "https://www.g2.com/categories/email-warm-up",
"host": "g2.com",
"title": "Best Email Warm-Up Software",
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [],
"ownedBy": "competitor.com",
"readState": "read",
"unreadableReason": "bot_protection",
"fetchedAt": "2026-09-04T10:00:00.000Z",
"textSource": "body",
"namesCustomer": "not_named",
"brandsNamed": [
"competitor.com",
"rival.io"
],
"excerpt": "…the most reliable options this year are Competitor Inc and Rival…"
}
]
}
],
"ownPageRetrievals": [
{
"engine": "perplexity",
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"pages": [
{
"key": "mycompany.com/pricing",
"url": "https://mycompany.com/pricing",
"title": "Pricing — My Company"
}
],
"companiesNamed": [
"competitor.com",
"rival.io"
],
"namedCustomer": false
}
],
"pages": [
{
"key": "g2.com/categories/email-warm-up",
"url": "https://www.g2.com/categories/email-warm-up",
"host": "g2.com",
"title": "Best Email Warm-Up Software",
"engines": [
"perplexity",
"google_ai_overviews"
],
"promptIds": [
"value"
],
"ownedBy": "competitor.com",
"readState": "read",
"unreadableReason": "bot_protection",
"fetchedAt": "2026-09-04T10:00:00.000Z",
"textSource": "body",
"namesCustomer": "not_named",
"brandsNamed": [
"competitor.com",
"rival.io"
],
"excerpt": "…the most reliable options this year are Competitor Inc and Rival…"
}
],
"limits": {
"pagesRetrieved": 153,
"pagesRead": 140,
"pagesUnreadable": 9,
"pagesNotFetched": 4,
"pagesTruncated": 3,
"unreadableByReason": {
"bot_protection": 5,
"host_blocked_recently": 2,
"text_too_short": 1,
"not_found_page": 0,
"consent_wall": 0,
"unreachable": 0,
"timeout": 1,
"fetch_failed": 0,
"unresolved": 0
},
"textSourceMix": {
"body": 140,
"snippet_only": 9,
"none": 4
},
"sentences": [
{
"code": "sources_retrieved_not_cited",
"text": "Retrieved, never cited: these are the pages the engine pulled back while answering; which of them it leaned on is not something the engines disclose."
}
]
}
},
"answers": [
{
"engine": "perplexity",
"promptIndex": 0,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools are safe to use with a Google Workspace domain?",
"intent": "safety",
"askedIn": {
"locationName": "United States",
"languageName": "English"
},
"answerText": "For a Google Workspace domain, the safest warm-up tools are Competitor Inc and Rival, both of which…",
"companiesNamed": [
{
"rank": 1,
"name": "Competitor Inc",
"domain": "competitor.com"
}
],
"sources": [
{
"url": "https://www.g2.com/categories/email-warm-up",
"domain": "g2.com",
"title": "Best Email Warm-Up Software",
"snippet": "Warm-up tools gradually increase sending volume so that mailbox providers…",
"publishedAt": "2026-05-12",
"resolvedFrom": "https://www.google.com/goto?url=…"
}
],
"searchQueries": [
"email warm-up tools Google Workspace safe"
],
"webSearch": {
"performed": true,
"completedSearchCount": 3,
"reason": "NO_SEARCH_ATTEMPTED"
}
}
],
"unansweredQueries": [
{
"engine": "perplexity",
"promptIndex": 5,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools have a free plan?",
"reason": "no_usable_answer"
}
],
"noAnswerShown": [
{
"engine": "google_ai_overviews",
"promptIndex": 3,
"promptId": "7f3c1a2e-9d44-4c8b-9f0e-2b6a5c9d7e10",
"promptText": "Which email warm-up tools have a free plan?",
"reason": "no_ai_overview_shown"
}
],
"engineStatus": {
"perplexity": {
"reported": true,
"completedAt": "2026-09-04T10:00:00.000Z",
"questionsAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0
},
"google_ai_overviews": {
"reported": true,
"completedAt": "2026-09-04T10:00:00.000Z",
"questionsAsked": 8,
"answersReceived": 7,
"answersAbsent": 1,
"answersUnmeasured": 0
}
},
"answersTruncated": false
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_parameters · invalid_run_id · invalid_check_id | Bad request — the payload failed validation. |
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
| 404 | check_not_found · run_not_summarized | No check matches the id in the path. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "invalid_parameters",
"message": "Domain is required",
"status": 400
}
}