Worked analytics queries
Every operation below is documented on this page with its parameters, but the bodies you branch on — the KPI envelope, the breakdown rows, the totals line — are easiest to learn as one reader chain: pick a metric/summary endpoint → filter by period and channel → page through the breakdown rows → read the totals row. The samples below walk that chain end to end and show the full response envelope at each step. Scope of this overlay:- Per the language note above, these samples show cURL and TypeScript — the two most-requested languages. The other four tabs appear on the endpoint blocks themselves.
- The full endpoint catalogue with every filter combination lives at the stats API guide; recurring email delivery of the same data (schedule, recipients, cadence) is covered in scheduled reports. This overlay stays envelope-accurate: request, response, and the errors that decide what you branch on — nothing else.
200 — during a transient storage
blip, so a poll loop or an always-on dashboard never flashes a 5xx; design
your polling against that contract.
1. Pull a KPI summary
GET /api/v1/analytics/messages returns the headline KPIs for a period —
sent, delivered, failed, read, the derived rates, and the average delivery
time — plus a bucketed time series for charting. Filter the window with
start_date / end_date (or a days lookback) and narrow to one channel
with channel.
200
data.totals, chartable buckets under data.time_series (or a named
breakdown array), and the echoed granularity under data.group_by. The
cost counterpart — GET /api/v1/analytics/costs — answers with the same
totals + time_series envelope plus a by_channel breakdown.
2. Page a breakdown series
Breakdown endpoints return the counters you just read, re-sliced per dimension — channel, destination country, or error code behind failures. Page through the list endpoints that carry a cursor (for example goals): keep the same filters, pass the previous page’snextCursor back as
cursor, and stop when it comes back null.
GET /api/v1/analytics/goals
200
cursor=cur_8Kw2mQ1z; when this page’s nextCursor is null
you have the full set:
200
GET /api/v1/analytics/messages/by-channel,
/by-country, and /messages/errors — are single-response reads with no
cursor; each returns its full ranked array (channels, countries,
errors) so you render them directly.
3. Prebuilt report read (and the empty-period shape)
GET /api/v1/analytics/scheduled-reports lists the recurring reports
already scheduled for your organization — the prebuilt views the scheduler
emails on a cadence — with each report’s type, frequency, recipients, and
its last- and next-send timestamps.
200
200 with zeroed totals and an empty series — test
your client against this shape so a quiet period never parses as a failure:
200
4. Errors
Two branches cover the mistakes callers actually hit on this surface. Validation — unrecognized filter value. Query params are validated before any query runs. A failed validation returns422 VALIDATION_ERROR
with error.details.issues listing each rejected field — for example a
group_by outside the allowed set (hour / day / week / month):
422
403 INSUFFICIENT_PERMISSIONS and a message naming the accepted roles:
403
422 needs a corrected filter
before you re-send, and a 403 will not succeed until the role changes.