Not available yet. These routes are designed and the queries behind them are built; the routes themselves are not. This page describes the planned surface. When it ships, this reference is generated from the same schemas the API validates against, so it cannot drift from the implementation.
Base URL: https://truestat.io/api/v1/
All endpoints are GET. All are read-only. All need
an API key on the Pro tier.
The endpoints
| Method | Path | Returns |
GET | /sites | The sites this key can read — start here for the ids |
GET | /sites/{id}/overview | The headline totals. One small answer. |
GET | /sites/{id}/timeseries | Bucketed views and visitors over time |
GET | /sites/{id}/breakdowns/{dimension} | A ranked breakdown |
GET | /sites/{id}/summary | Everything the dashboard renders, in one call |
GET | /sites/{id}/ai/crawlers | Crawler views by operator, with verification |
GET | /sites/{id}/ai/pages | Which of your pages crawlers read |
GET | /usage | Your event limit and consumption this period |
Which one to call
/overview for a single number on a status page. It is one query.
/summary for a full dashboard rebuild. It fans out across every breakdown,
so it is a much heavier call — do not poll it every 30 seconds for one figure.
/timeseries and /breakdowns/{dimension} for anything in between.
Breakdown dimensions
pages · referrers · channels · campaigns · keywords · countries ·
regions · cities · browsers · os · devices
channels and keywords have no equivalent in comparable products.
One-site keys
If a key is scoped to exactly one site, the {id} segment can be omitted —
/api/v1/summary resolves to that site. It is a convenience only; the same
authorisation runs either way.
Shared parameters
Apply to /overview, /timeseries, /breakdowns/*, /summary and both /ai/*
endpoints.
| Parameter | Contract |
from, to | ISO 8601. Must be given together — one alone is a 400. |
period | Instead of from/to: today, yesterday, last24h, last7d, last30d, last12m, month, year, all. Resolved in the site's timezone. Combining it with from/to is a 400. |
tz | IANA timezone name. Defaults to the site's own. |
unit | Timeseries only: minute, hour, day, week, month. |
limit, offset | Breakdowns only. limit defaults to 100, maximum 1000. offset defaults to 0. |
bots | excluded (default) or included. Ignored by the /ai/* endpoints, which always include crawlers. |
filter_* | See below. |
Filters
Flat query parameters, one per dimension:
filter_path filter_path_pattern filter_browser
filter_os filter_device filter_country
filter_region filter_city filter_referrer
filter_channel filter_utm_source filter_utm_medium
filter_utm_campaign filter_utm_term filter_bot_kindEquality only. There is no is_not, no contains and no numeric comparison.
The one exception is filter_path_pattern, which accepts * as a wildcard:
?filter_path_pattern=/blog/*filter_bot_kind applies to the /ai/* endpoints and takes ai_assistant,
ai_training, search or other.
Retention clamping
If your range reaches further back than your tier's retention window, you get the data that exists and the response says so — not an error, and not a silent truncation:
"meta": { "range": { "clamped": true, "from": "2023-08-24T00:00:00Z" } }Retention is 3 years on Starter and 5 on Pro, and the API reads the same window the dashboard does. See Data retention.
The response envelope
One shape, on every endpoint, with no exceptions:
{
"data": { },
"meta": {
"site_id": "…",
"range": { "from": "…", "to": "…", "tz": "UTC", "clamped": false },
"unit": "day",
"bots": "excluded",
"pagination": { "limit": 100, "offset": 0 }
}
}Errors use one shape too, with a symbolic code rather than a repeated HTTP status:
{ "error": { "code": "insufficient_scope", "message": "…" } }error.message never contains anything from your request. See
Errors.
Adding a field to data is not a breaking change. Read the fields you need
and ignore the rest.
Pagination
limit and offset on breakdowns. There is no cursor.
meta.pagination carries limit and offset and not a total, because the
underlying queries do not compute one. Rather than fabricate a number, it is
absent. To tell whether more rows exist, ask for one more than you need.
What is not here, and will not be
| Why | |
/visitors, /visitors/{id} | Needs cross-day person identity TrueStat is built without. Not deferred — not this product. |
| Anything writing events | Use the tracking script. |
| Revenue, payments, goal analytics, funnels | Those features do not exist. |
| Site, key, team and settings management | Dashboard only. Every write endpoint is authorisation surface with no demand behind it. |
fields projection | Rows are two or three columns. A projection layer would buy nothing. |
What is deferred, not refused
| Note | |
/realtime | A live visitor count. Cheap and genuinely wanted; first candidate after the initial set. |
| Bounce rate, session duration | Not on the dashboard either. Those come first. |
Filter operators (is_not, contains) | Would mean rewriting the predicate every dashboard number flows through. Deliberate, or not at all. |
| Hostname breakdown | For multi-domain sites. |
| An MCP server | Designed to be a thin adapter over these routes once they exist. |