GET /api/v1/analytics/status
Where collection stands
Queue depth, per-channel readiness and spending. failed, blocked and budgetExhausted are three figures with three different owners and are never summed.
Responses
200 The current state.401 Missing, unknown or revoked key.403 The key does not carry analytics:read.
GET /api/v1/analytics/channels
What Carqo can ask, and what each channel is not
Implemented, configured and live verified are three separate columns. Consumer surfaces are listed as unsupported rather than omitted, because absence from a list reads as an oversight.
Responses
200 The channel catalogue and coverage matrix.
GET /api/v1/analytics/prompt-sets/{promptSetId}/prompts
The questions, as revisions
Revisions rather than prompts. A reworded question becomes a new revision, and answers already collected stay pointed at the old one. Grouping by prompt id would mix two different questions.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
Responses
200 Current revisions.404 No such question set.
GET /api/v1/analytics/prompt-sets/{promptSetId}/visibility
Visibility, citations and competitors, with denominators
presence was added on 27/10/2026 and nothing else changed. presence.window gives the whole London days the two figures are over. If the figures cannot be calculated, both are null and presence.unavailable explains why. presence.steadyPresence and presence.namedFirst each carry metric, state, reason, value, numerator, denominator, sampleCount, smallSample, excluded and explanation. A value of null means there was nothing to count, never zero. smallSample is true under 30. steadyPresence counts question and channel pairs named on half or more of their checked days. A checked day is a London day with a counted answer for that pair. An answer cut short that did not name the business is not counted. Only pairs checked on at least pairs.minimumDays separate days are counted. pairs.steady and pairs.occasional split those pairs. pairs.notEnoughDaysCount is how many pairs had fewer days, and they are never classed. pairs.notEnoughDays lists every one of them, each with promptRevisionId, channelId, provider, surface and checkedDays. channelId is null where no schedule collected the answers, and provider and surface then tell the pairs apart. The analytics MCP tool get_visibility lists only the first 10 of them and adds pairs.notEnoughDaysNote. The count is still the whole count. namedFirst counts the ordered lists that named the business at place 1, out of the ordered lists that gave it a place. Ordered lists that named the business with no place are left out and counted under excluded.list_position_unknown.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
from query, Optional
Start of the window, inclusive. Defaults to thirty days before to.
to query, Optional
End of the window. Defaults to now. Windows longer than 366 days are refused.
captureMode query, Optional
string- One of
provider_api, manual_ui, authorised_browser
Defaults to provider_api. Cohorts are never mixed, because a figure over API answers and one over records a person typed are different claims.
Responses
200 Figures for the window.400 Unusable window.
GET /api/v1/analytics/prompt-sets/{promptSetId}/trend
The same figures over time, with a denominator on every period
A period with no valid observation carries a null rate, never a zero, and a period with nothing scheduled is absent rather than zeroed. sufficientForDirection is false below three periods, because two points are not a trend. The payload says so rather than leaving a consumer to know the rule.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
from query, Optional
Start of the window, inclusive. Defaults to thirty days before to.
to query, Optional
End of the window. Defaults to now. Windows longer than 366 days are refused.
captureMode query, Optional
string- One of
provider_api, manual_ui, authorised_browser
Defaults to provider_api. Cohorts are never mixed, exactly as on the visibility path.
dimension query, Optional
string- One of
surface, prompt, entity, market - Default
surface
market is the country that was actually SENT to the provider, and it is not the locale. A locale is the language the question was written in. Grouping a location trend by locale would describe something else entirely.
buckets query, Optional
integer- Default
6 - Lowest
2 - Highest
24
The window is divided into this many equal, non-overlapping periods, oldest first. Equal because two periods of different lengths are not comparable, and non-overlapping because an answer counted twice is counted twice.
Responses
200 The series, per period and per key, each with its own denominator.400 Unusable window, dimension or bucket count.
GET /api/v1/analytics/prompt-sets/{promptSetId}/sources
What the answers cited, by domain
providerMade and proseOnly are separate counts. A URL that merely appeared in prose is not a citation the provider made.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
from query, Optional
Start of the window, inclusive. Defaults to thirty days before to.
to query, Optional
End of the window. Defaults to now. Windows longer than 366 days are refused.
GET /api/v1/analytics/prompt-sets/{promptSetId}/questions
Figures for each question, with its stage
Each row is one wording of one question, with asked, cameBack, settled, named and notNamed. rate is named over settled, and null where no answer settled it, never zero. stage is learning, comparing, buying or other. It comes from the words of the question, or the stage the owner chose for it. It does not measure what people want or how many ask. Rows come in the report's own order, questions doing worst first. Gaps come first, then the lowest rate, then the most answers settled. The order is not a ranking. limit and offset page through the rows, and nextOffset is where the next page starts, or null on the last. Only the first 500 rows can be read. rowsTotal is how many wordings there are, and cut is true when some cannot be read. An offset at or past the last readable row gives no rows, with the total still stated. Where the figures cannot be read, unavailable says why and the list is empty.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
from query, Optional
Start of the window, inclusive. Defaults to thirty days before to.
to query, Optional
End of the window. Defaults to now. Windows longer than 366 days are refused.
captureMode query, Optional
string- One of
provider_api, manual_ui, authorised_browser
Defaults to provider_api. Cohorts are never mixed.
limit query, Optional
integer- Default
100 - Lowest
1 - Highest
500
How many question wordings to list. A value over the maximum is held to it. A value that is not a whole number of 1 or more is refused.
offset query, Optional
How many rows to skip, in the order the rows come. A value that is not a whole number of 0 or more is refused.
Responses
200 The questions and their figures.400 Unusable window. A limit that is not a whole number of 1 or more. An offset that is not a whole number of 0 or more.404 No such question set.
GET /api/v1/analytics/prompt-sets/{promptSetId}/source-types
Cited websites by type, and cited pages by kind
The type lines count only websites an answer cited. A type comes from the address of the website, and a kind of page from words in its address. No page is opened. websitesTotal counts every website found, including websites that were only linked in the text or not cited. It can be more than the websites in the type lines. typeLines.own is the business's own website, kept apart from the other types. answersCitingOthersOnly counts answers that cited a website and never the business's own, and is null while the website is not verified. While nothing is measured, that figure, answersWithCitation, websitesShown and websitesTotal are null. typeLines and pageKinds are null while nothing is measured. When the list of websites or the list of pages was cut, cut is true and cutNote says what is counted.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
from query, Optional
Start of the window, inclusive. Defaults to thirty days before to.
to query, Optional
End of the window. Defaults to now. Windows longer than 366 days are refused.
captureMode query, Optional
string- One of
provider_api, manual_ui, authorised_browser
Defaults to provider_api. Cohorts are never mixed.
Responses
200 The type lines and the page kinds.400 Unusable window.404 No such question set.
GET /api/v1/analytics/prompt-sets/{promptSetId}/league
Businesses named in two or more answers
This path takes no window. It reads two periods of seven London days, the one ending on the day of the newest stored answer and the seven days before it. current and previous give the first and last day of each and the answers read in it. Another business named in fewer than two answers in the current period has no row. namedTotal still counts the names left out, so the shares can add up to less than 100. Your own business's row, where there is one, can show 0 or 1, because the two-answer rule applies to other businesses. In each row, answersNaming is a count of answers, and mentionRate and shareOfVoice are percentages. averagePosition and namedFirst are null where the name was never in a list. namedFirst is a fraction from 0 to 1, not a percentage. changePoints is null where the earlier period held too few answers. capped is true when the read stopped at 6,000 answers, so older answers may be missing. changePoints is then null. more is how many businesses were left out because the list holds at most 50 rows. The business itself has you set. Rows follow the mention rate. No row has a place or a rank. A name may be a directory or a supplier. notes holds the workspace page's own words on what the list is and is not. emptyNote is set only when the list has no row at all. Where no answer was read, answersRead is 0, more is 0 and capped is false. The other figures are null. A key may call this path 10 times a minute.
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
Responses
200 The league.404 No such question set.429 More than 10 league requests on this key in a minute.
GET /api/v1/analytics/prompt-sets/{promptSetId}/runs
Collection runs, paged
Parameters
promptSetId path, Required
A question set in the workspace the key belongs to. A set in another workspace answers 404, the same as one that does not exist.
limit query, Optional
integer- Default
50 - Highest
200
cursor query, Optional
Opaque. Read from the previous nextCursor, never built by hand. It carries the last row's requestedAt and id together, at the microsecond precision the column holds, not the millisecond a Date can round-trip. A keyset cursor rather than an offset, so a concurrent insert cannot make a consumer skip a row. It carries no tenant and no filter, and a cursor that does not parse is ignored rather than erroring. The response says so in cursorRejected.
Responses
200 A page of runs, with nextCursor (null once there is no next page) and cursorRejected (true only when a supplied cursor could not be read).