Base URL and authentication
GET /v1/sources/breakdown takes Authorization: Bearer <YOUR_API_KEY> (details) and the stats:read permission. Its site_id is the site’s snippet key, the ttid_ value your install snippet carries as data-site, which you can read from GET /v1/sites.
GET /v1/sources, at the bottom of this page, is different on both counts: a dashboard session only, and a UUID.
GET /v1/sources/breakdown
One row per day per source, with attributed revenue joined on. This is the data behind the Sources page in the dashboard.
Choosing the window
Send eitherfrom and to together, or days. If you send neither, the window is the last 7 days.
Two limits apply to
from and to:
- The range may not span more than 730 days.
frommay not be more than 730 days ago.
0.0% bounce rate instead of telling you the data is gone. It is refused instead.
Response fields
Each
breakdown row:
About the two revenue fields
revenue_usd_cents is how revenue is stored: integer US cents, so it never drifts through rounding.
revenue_display is the same amount in your site’s reporting currency. Each day converts at that day’s exchange rate, so a figure you read last month does not change when rates move.
If we hold no rate for one of the dates in your window, that row’s revenue_display is null and the date is listed in missing_rate_dates. It is never the US dollar figure relabelled with your currency.
If your reporting currency is USD, no conversion happens: converted is false and revenue_display equals revenue_usd_cents / 100.
ai_source is a source label, not an AI flag
ai_source also carries non-AI values (direct, organic_search, social, email, paid, referral), so summing every row gives you total traffic rather than AI traffic. total_sessions is that same total, computed independently.
Errors
GET /v1/sources
The distinct source keys seen for a site: the ai_source values actually observed in the window,
plus the fixed list of non-AI channels. The dashboard uses it to populate its source filter.
Two things differ from every other read on this page. site_id is the site’s Postgres id (a UUID),
not the ttid_ snippet key, and the window is days rather than from and to.
ai depends on the window. non_ai is a fixed list and does not. This is one of the endpoints that
predates the { status, data } envelope, so the object above is the whole body.
If the underlying query fails, ai comes back empty with a 200 and no caching headers, rather
than an error. Treat an empty ai as “no answer right now”, not as “no AI traffic”.
Next
- Recent events for individual events rather than daily totals
- Goals and funnels for conversion reporting

