GET /sites/competitor_sentiment
Returns sentiment counts for your site and each competitor, one row per brand per series. Built for BI tools: every row has the same columns, with or without dates, so it maps directly into a table.
Without dates, rows cover the latest refresh compared to the refresh before
it. With start_date/end_date, rows cover that period compared to the
previous period.
Request
Endpoint
https://knowatoa.com/api/v2/sites/competitor_sentiment
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 (each row includes the site and account columns) |
| format | string | No | Set to "csv" for CSV export (same columns as flat JSON) |
| start_date | string | No | Period start (YYYY-MM-DD). See Period Comparison |
| end_date | string | No | Period end (YYYY-MM-DD), inclusive |
| compare_start | string | No | Comparison period start. Defaults to the equal-length period before start_date |
| compare_end | string | No | Comparison period end, inclusive |
Response
Nested JSON Format
{
"site": {
"id": "tpc_abc123",
"name": "Example Site",
"url": "https://example.com",
"external_id": "example.com"
},
"period": { "start": "2025-01-15", "end": "2025-01-15", "refresh_count": 1 },
"compare_to": { "start": "2025-01-08", "end": "2025-01-08", "refresh_count": 1 },
"competitor_sentiment": [
{
"competitor_id": "tpc_def456",
"competitor_name": "Rival Co",
"is_target": false,
"series_id": "spx_xyz789",
"series": "ChatGPT",
"metrics": {
"mentions": { "current": 11, "previous": 9, "change_points": 2, "change_percent": 22.2 },
"positive_count": { "current": 6, "previous": 5, "change_points": 1, "change_percent": 20.0 },
"...": "..."
}
}
]
}
Flat JSON and CSV
One row per brand per series. Each metric becomes four columns:
<metric>_current, <metric>_previous, <metric>_change_points,
<metric>_change_percent (for example positive_count_current). Rows also
carry account_id, account_name, site_id, site_name, external_id,
period_start and period_end. The comparison dates are only in the
nested JSON (compare_to).
Fields
| Field | Type | Description |
|---|---|---|
| competitor_id | string | Brand ID. For your own site this equals site_id |
| competitor_name | string | Brand name |
| is_target | boolean | True for your own site’s row |
| series_id, series | string | AI service |
| mentions | integer | All mentions, including ones not scored yet |
| sentiment_evaluated | integer | Mentions with a sentiment score |
| positive_count, neutral_count, negative_count | integer | Mentions in each sentiment bucket |
| positive_percent, neutral_percent, negative_percent | float | Share of evaluated mentions, or null when nothing was evaluated |
| sentiment_score | float | Average sentiment score from -1 to 1, or null when nothing was evaluated |
Notes
- Sentiment buckets: score ≤ -0.1 is negative, ≤ 0.1 is neutral, above 0.1 is positive. These are the same thresholds used for the stored sentiment label
- Only completed AI responses count. History recorded under an AI model the series has since replaced still counts
- A window with no data reports null rather than 0
- Every brand gets a row for every series, including series with zero mentions. Your site comes first, then competitors by name
- When loading repeated pulls, dedupe on site_id + period_start + period_end + competitor_id + series_id
- Only available for target sites (not competitors)
- The scheduled “Competitor Sentiment” CSV export keeps its existing wide layout