<Intro>

<EndpointHeader />

<Description>

Returns aggregate delivery and latency stats grouped by tag (`name:value`) for the requested period. Rows are ranked by the `sort` metric (default `accepted`) descending and capped at the requested `limit` (default 50, hard maximum 200). Use this to compare delivery performance across the campaigns, experiments, or segments you tag your sends with.
Only tagged messages appear. A message carrying several tags is counted once under each of them, so rows do not sum to the period total.
Rows are attributed to send time, not event time: a delivery confirmed during the period for a message accepted earlier counts against the earlier period, not this one. A recent period therefore under-reports `delivered` while its delivery reports are still arriving, and its counts only ever grow toward the truth.
The maximum window is 365 days; requesting a longer range returns 422.

</Description>

</Intro>

<Parameters in="query">

<Parameter name="from" type="string">

<Description>

Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to keep the window within the 720-hour trend cap.

</Description>

</Parameter>

<Parameter name="to" type="string">

<Description>

End date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to today in that timezone when omitted. Window may not exceed 365 days.

</Description>

</Parameter>

<Parameter name="timezone" type="string">

<Description>

IANA timezone identifier (for example `Asia/Kathmandu`) to report in; defaults to UTC. Day and hour boundaries and the default window when `from` and `to` are omitted both follow it, so a calendar-day `from` or `to` names a local day. A `from` or `to` carrying its own UTC offset is rejected while this is set: pass a calendar day or a `Z` instant.

</Description>

</Parameter>

<Parameter name="sort" type="string">

<Description>

Metric to rank rows by, applied descending. Any lifecycle count or derived rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `accepted`.

</Description>

<Description>

Possible values: `accepted`, `sent`, `delivered`, `undelivered`, `failed`, `rejected`, `expired`, `delivery_rate`, `failure_rate`

</Description>

</Parameter>

<Parameter name="limit" type="integer">

<Description>

Maximum number of tag rows to return, ranked by the `sort` field descending.

</Description>

</Parameter>

<Parameter name="include_trend" type="boolean">

<Description>

When true, each row also carries a `trend` array: a short per-bucket lifecycle-count series for that row over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422.

</Description>

</Parameter>

<Parameter name="trend_grain" type="string">

<Description>

Bucket grain for the `trend` series. Has no effect unless `include_trend=true`.

</Description>

<Description>

Possible values: `daily`, `hourly`

</Description>

</Parameter>

</Parameters>

<Payload kind="response">

<Field name="period" type="object" required>

<Description>

The date range the response covers (echoed back from the request), plus `data_as_of`, the freshness boundary the data is current to.

</Description>

<FieldChildren kind="response">

<Field name="from" type="string" prefix="period." required>

<Description>

Inclusive start of the window the response covers -- a calendar day (YYYY-MM-DD) for day windows, or an hour boundary (RFC 3339) for hour windows.

</Description>

</Field>

<Field name="to" type="string" prefix="period." required>

<Description>

Inclusive end of the window the response covers -- a calendar day (YYYY-MM-DD) for day windows, or an hour boundary (RFC 3339) for hour windows.

</Description>

</Field>

<Field name="data_as_of" type="nullable string" prefix="period.">

<Description>

The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response is near-real-time but not live; use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="data" type="array of object" required>

<Description>

Tag breakdown rows, ranked by the `sort` metric (default `accepted`) descending. Empty when no tagged messages were sent in the period.

</Description>

<FieldChildren kind="response">

<Field name="tag" type="string" prefix="data." required>

<Description>

The tag this row aggregates, in `name:value` form. Each distinct name-and-value pair is its own row, and a message carrying several tags is counted once under each of them, so rows do not sum to the period total.

</Description>

</Field>

<Field name="delivery" type="object" prefix="data." required>

<FieldChildren kind="response">

<Field name="accepted" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages accepted for sending after admission checks. This is the denominator for `delivery_rate` and `failure_rate`.

</Description>

</Field>

<Field name="sent" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages handed off to the carrier for delivery.

</Description>

</Field>

<Field name="delivered" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages the carrier confirmed as delivered to the handset.

</Description>

</Field>

<Field name="undelivered" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages the carrier reported as not delivered.

</Description>

</Field>

<Field name="failed" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages that failed during sending.

</Description>

</Field>

<Field name="rejected" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages rejected before any send attempt, for example by sending policy or a message-generation failure.

</Description>

</Field>

<Field name="expired" type="integer" prefix="data.delivery." required>

<Description>

Distinct messages that could not be delivered within their validity window and expired.

</Description>

</Field>

<Field name="delivery_rate" type="nullable number" prefix="data.delivery." required>

<Description>

Share of accepted messages that were delivered, computed as `delivered / accepted`. Null when no messages were accepted in scope.

</Description>

</Field>

<Field name="failure_rate" type="nullable number" prefix="data.delivery." required>

<Description>

Share of accepted messages that ultimately failed, computed as `(undelivered + failed + expired) / accepted`. Null when no messages were accepted in scope.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="latency" type="object" prefix="data." required>

<FieldChildren kind="response">

<Field name="processing" type="object" prefix="data.latency.">

<Description>

p50, p95, and p99 latency percentiles in milliseconds for one latency family over the scope. Percentiles are approximate (computed from a high-volume aggregation pipeline). All three are null together when no qualifying event contributed a latency measurement in scope.

</Description>

<FieldChildren kind="response">

<Field name="p50_ms" type="nullable integer" prefix="data.latency.processing." required>

<Description>

Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p95_ms" type="nullable integer" prefix="data.latency.processing." required>

<Description>

95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p99_ms" type="nullable integer" prefix="data.latency.processing." required>

<Description>

99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="delivery" type="object" prefix="data.latency.">

<Description>

p50, p95, and p99 latency percentiles in milliseconds for one latency family over the scope. Percentiles are approximate (computed from a high-volume aggregation pipeline). All three are null together when no qualifying event contributed a latency measurement in scope.

</Description>

<FieldChildren kind="response">

<Field name="p50_ms" type="nullable integer" prefix="data.latency.delivery." required>

<Description>

Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p95_ms" type="nullable integer" prefix="data.latency.delivery." required>

<Description>

95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p99_ms" type="nullable integer" prefix="data.latency.delivery." required>

<Description>

99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="total" type="object" prefix="data.latency.">

<Description>

p50, p95, and p99 latency percentiles in milliseconds for one latency family over the scope. Percentiles are approximate (computed from a high-volume aggregation pipeline). All three are null together when no qualifying event contributed a latency measurement in scope.

</Description>

<FieldChildren kind="response">

<Field name="p50_ms" type="nullable integer" prefix="data.latency.total." required>

<Description>

Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p95_ms" type="nullable integer" prefix="data.latency.total." required>

<Description>

95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

<Field name="p99_ms" type="nullable integer" prefix="data.latency.total." required>

<Description>

99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.

</Description>

</Field>

</FieldChildren>

</Field>

</FieldChildren>

</Field>

<Field name="trend" type="array of object" prefix="data.">

<Description>

Per-bucket lifecycle-count series for this tag over the window, bucketed by `trend_grain`. Sparse, so only buckets with activity are present rather than zero-filled, unlike the daily and hourly series. Present only when `include_trend=true`.

</Description>

<FieldChildren kind="response">

<Field name="bucket" type="string" prefix="data.trend." required>

<Description>

The day (YYYY-MM-DD) or hour (RFC 3339, on the hour) this point covers, matching the period's grain.

</Description>

</Field>

<Field name="delivery" type="object" prefix="data.trend." required>

<FieldChildren kind="response">

<Field name="accepted" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages accepted for sending after admission checks.

</Description>

</Field>

<Field name="sent" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages handed off to the carrier for delivery.

</Description>

</Field>

<Field name="delivered" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages the carrier confirmed as delivered to the handset.

</Description>

</Field>

<Field name="undelivered" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages the carrier reported as not delivered.

</Description>

</Field>

<Field name="failed" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages that failed during sending.

</Description>

</Field>

<Field name="rejected" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages rejected before any send attempt, for example by sending policy or a message-generation failure.

</Description>

</Field>

<Field name="expired" type="integer" prefix="data.trend.delivery." required>

<Description>

Distinct messages that could not be delivered within their validity window and expired.

</Description>

</Field>

</FieldChildren>

</Field>

</FieldChildren>

</Field>

</FieldChildren>

</Field>

<Field name="total" type="integer" required>

<Description>

Total number of distinct tags with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.

</Description>

</Field>

</Payload>