Building queries
Shape an Analytics request: choose a timeframe (predefined or custom), set the timezone and output currency, break results down with group_by, narrow them with bounded filters, and attach a previous-period comparison.
Every Analytics report shares the same request grammar. Beyond the required statistics list (Statistics catalog), a handful of optional parameters control the window, the units, the breakdown and the comparison. They behave identically across families, so once you know them you can read any report.
Timeframe
Pick a window in one of two ways. Use a predefined key for the common cases, or start + end for an arbitrary range.
Predefined keys
Pass timeframe with one of:
today, yesterday, this_week, last_week, last_7_days, this_month, last_month, last_30_days, last_90_days, last_3_months, last_12_months, this_year, last_year.
If you omit timeframe, each family applies a sensible default that matches its fastest path (the account overview defaults to the last 3 months; campaigns to their lifetime; automations, flows and the transactional rollup to the last 30 days).
GET /project/{project}/analytics/overview
?statistics=delivered,click_rate
&timeframe=last_30_daysCustom range
Provide both start and end as ISO 8601 timestamps. When both are present they define the window and override timeframe.
GET /project/{project}/analytics/overview
?statistics=delivered,click_rate
&start=2026-05-01T00:00:00+02:00
&end=2026-05-30T23:59:59+02:00Windows are snapped to whole-hour boundaries in the resolved timezone (start snapped down, end snapped up). When snapping changes the bounds you asked for, the response carries a warning and echoes the actual window in its timeframe block.
Interval (series only)
Series reports bucket the window over time. Set interval to one of hour, day, week, month. The default is day regardless of how long the window is.
If your window and interval would produce too many buckets, the server automatically coarsens to the next grain and tells you via a warning; the report always echoes the effective interval it used. If even the coarsest grain does not fit, the request is rejected with a clear error asking you to narrow the window.
Timezone
Set timezone to any IANA zone (for example Europe/Madrid). It governs day, week and month boundaries and bucketing. The default is your project's timezone — never UTC and never the caller's local time. The resolved timezone is echoed in every response.
Currency
Set currency to an ISO 4217 code to receive every monetary statistic in that currency. The response echoes the output currency and the source_currency the data was stored in. Dimensionless statistics (roas, epm) are never converted.
Breakdowns with group_by
group_by splits a report into buckets along exactly one dimension. It is strictly single-dimension: multi-dimensional, nested or two-dimensional group_by is not supported and never will be. A request that passes more than one dimension is rejected with too_many_group_by_dimensions. There is no nested keying, no second dimension stacked under the first, and no per-outer roll-up — pass a single dimension.
The breakdown vocabulary is channel, country, language, gender, segment and communication_type. Which of these a given report accepts varies by report — see the support matrix below.
| Dimension | Cardinality |
|---|---|
channel | Closed enum — every bucket returned |
communication_type | Closed enum — every bucket returned |
gender | Closed enum — every bucket returned |
country | Open — top 20 buckets, no overflow bucket |
language | Open — top 20 buckets, no overflow bucket |
segment | Open — top 20 buckets, no overflow bucket |
Closed-enum dimensions return every bucket. Open-cardinality dimensions return the top 20 buckets ordered by your first requested statistic — there is no synthetic other bucket: the tail beyond the top 20 is simply not returned, never rolled up into an overflow bucket.
When you group by country, the bucket keys are the uppercase ISO 3166-1 alpha-2 code (ES, FR), plus an unknown bucket for recipients whose country could not be resolved.
To look at one dimension within another (countries within RCS, channels within Spain), don't stack two dimensions — pair a single group_by with a filter. See Cross-cutting two dimensions.
When you group, the response switches to the grouped shape: a values report keys statistics by group, a series report keys series by group, and both add a totals_per_group roll-up plus a group_order ranking — see Grouped values and Grouped series.
GET /project/{project}/analytics/overview/series
?statistics=delivered,clicks_first
&timeframe=last_30_days
&group_by=channelFilters
filter narrows a report to a subset before aggregating. There is no raw query language — only a closed set of keys, each validated against a fixed enum. Use bracket syntax:
?filter[channel]=sms&filter[country]=ESThe two general filter keys are channel and country. Every other breakdown dimension — language, gender, segment, communication_type and sender — is group_by-only and is never a filter; passing it as a filter key returns a 400, as does any value outside the closed enum. One report adds a third key of its own: the flow report accepts version (see Flow reports), which no other family does and which is never a group_by dimension.
Which filters a given report honors varies by report — see the support matrix. A report rejects any filter key it does not support.
Country filter values are the ISO 3166-1 alpha-2 code and are case-insensitive on input — filter[country]=ES and filter[country]=es are equivalent. Group-by country bucket keys, by contrast, are always returned uppercase (ES), with an unknown bucket for unresolved recipients.
Cross-cutting two dimensions
Because group_by is single-dimension, you look at one dimension within another by pairing a single group_by with a filter on the other dimension — not by stacking two group_by values. This works on any report that supports both that group_by and that filter (see the support matrix — for example, the campaign and automation reports honor both channel and country):
| Goal | Request |
|---|---|
| Countries within RCS | filter[channel]=rcs + group_by=country |
| Channels within Spain | filter[country]=ES + group_by=channel |
| RCS totals only | filter[channel]=rcs (no group_by) |
| Spain totals only | filter[country]=ES (no group_by) |
GET /project/{project}/analytics/campaign/{campaign}
?statistics=delivered,clicks_first
&filter[channel]=rcs
&group_by=countryFiltering and grouping on the same dimension is redundant and rejected (filter[channel]=rcs + group_by=channel).
Which report supports what
group_by and filter are expressed identically everywhere, but each report accepts its own subset — and each report rejects any dimension it does not support. This matrix is the authoritative reference; a report's own reference page repeats its row.
| Report | group_by | filter |
|---|---|---|
| Account overview — values & series | channel, country, language, gender, segment, communication_type | country |
| Campaign report — values | channel, country | channel, country |
| Campaign report — series | channel, country | channel, country |
| Automation report — values | channel, country | channel, country |
| Automation report — series | channel, country | channel, country |
| Flow report — series | channel, country | channel, country, version |
| Direct / transactional rollup — values & series | channel, country | channel, country |
A few consequences worth calling out:
- The account overview is the only report that accepts the full breakdown catalog, but it filters by
countryonly. - The campaign, automation and transactional rollup reports all behave the same on both their values and series: they break down and filter by
channelandcountry, so the cross-cut works on every one of them (e.g.filter[country]=ES+group_by=channel, orfilter[channel]=rcs+group_by=country). - The flow report has no values shape — it is a series only — and it is the one report with a third filter key,
version. It combines with the others, sofilter[version]=…+group_by=channelgives you one version's per-channel series. - The transactional rollup's
group_by=channelseries is the per-leg series of a fallback chain.
Comparison
On values reports, set compare_to=previous_period to attach a comparison block: the natural "before" window, the same statistics, and the per-statistic change (absolute and percentage).
- Accepted for the account overview, automations and the transactional rollup.
- Rejected for standard campaigns — a campaign is a one-shot send with no previous period. To compare campaigns, use the campaign compare endpoint instead.
- Not applicable to flows — the flow family is a series report only, and comparison is a values-report feature. To weigh one flow version against another, scope two series calls with
filter[version]— see Comparing two versions.
?compare_to=previous_periodSee Reading results for the comparison shape, and the campaign / automation compare reports for ranking several entities at once.