GET /sites/negative_mentions
Returns every AI answer that describes the site negatively, so you can see which questions and AI services drive negative sentiment and why.
Request
Endpoint
https://knowatoa.com/api/v2/sites/negative_mentions
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| site_id | string | Yes | Site prefix ID (e.g., tpc_abc123) |
| api_key | string | Yes | Your API authentication key |
| flat | string | No | Set to "true" for flat JSON format (mention rows only) |
| format | string | No | Set to "csv" for CSV export (mention rows only) |
| start_date | string | No | Period start (YYYY-MM-DD). With end_date, covers every refresh in the period instead of the latest refresh. See Period Comparison |
| end_date | string | No | Period end (YYYY-MM-DD), inclusive |
| compare_start | string | No | Comparison period start for metrics. Defaults to the equal-length period before start_date |
| compare_end | string | No | Comparison period end, inclusive |
| series_id | string | No | Only this AI service (series prefix ID) |
| sort | string | No | most_negative (default): lowest score first. question_negatives: questions with the most negative answers first. series_negatives: AI services with the most negative answers first |
| limit | integer | No | Mentions per page. Max 100. Default 25 for nested JSON, 100 for flat JSON and CSV |
| offset | integer | No | Mentions to skip. Use next_offset from the previous page |
Response
Nested JSON Format
{
"site": { "id": "tpc_abc123", "name": "Example Site", "url": "https://example.com", "external_id": "example.com" },
"period": { "start": "2026-09-01", "end": "2026-09-30", "refresh_count": 4 },
"compare_to": { "start": "2026-08-02", "end": "2026-08-31", "refresh_count": 4 },
"metrics": {
"negative_count": { "current": 6, "previous": 9, "change_points": -3, "change_percent": -33.3 },
"sentiment_evaluated": { "current": 40, "previous": 38, "change_points": 2, "change_percent": 5.3 }
},
"sort": "most_negative",
"total_negative": 6,
"limit": 25,
"offset": 0,
"by_question": [
{ "question_id": "qst_abc", "question": "Best apartments near downtown?", "negative_count": 3, "average_score": -0.42 }
],
"by_series": [
{ "series": { "id": "spx_xyz", "name": "ChatGPT" }, "negative_count": 4, "average_score": -0.35 }
],
"mentions": [
{
"refresh_date": "2026-09-15",
"question_id": "qst_abc",
"question": "Best apartments near downtown?",
"series": { "id": "spx_xyz", "name": "ChatGPT" },
"sentiment_score": -0.6,
"sentiment_label": "Very Negative",
"excerpt": "Example Site has frequent maintenance complaints.",
"competitors_mentioned": ["Rival Apartments"],
"citations": [{ "url": "https://www.reddit.com/r/example/1", "domain": "reddit.com" }]
}
]
}
Without start_date/end_date, period, compare_to, and metrics are
replaced by refresh_date (the latest refresh). next_offset is present when
more mentions remain.
Flat JSON and CSV
One row per mention: site_id, site_name, external_id, refresh_date,
question_id, question, series_id, series, sentiment_score,
sentiment_label, excerpt, competitors_mentioned (comma-separated),
citation_domains (comma-separated), citation_urls (space-separated), and
total_negative (every negative mention, on every row). CSV always includes
the header row.
These formats are paginated with limit/offset like the nested format, so
one request returns at most 100 rows. Each response sets:
X-Total-Count: every negative mention matching the request.X-Next-Offset: theoffsetfor the next page. Absent on the last page.
These formats default to 100 rows per page. To export everything, repeat the request with offset set to
X-Next-Offset until it is absent. If your tool can’t read headers, stop when
the rows you’ve collected reach total_negative.
Notes
- A mention is negative when its sentiment score is -0.1 or lower (labels: “Very Negative” at -0.5 or lower, otherwise “Negative”).
excerptis the sentences in the answer that name the site, matched with the site’s current brand words and prepared the way the sentiment scorer prepares them (capped at 4,000 characters). If brand words changed after the answer was scored, the excerpt can differ from what was scored, or be empty.by_questionandby_seriescover every negative mention, not just the current page, and are sorted bynegative_count, then lowest average score.- Only tracked questions and the AI services on your plan are counted. If a
model upgrade leaves two models of one AI service on a refresh, only the
newer model counts, so
total_negativematchesnegative_countfromsites/sentimentfor the same period.