Statistics

Counts by period, event, tag, type and sending domain — read from a daily rollup, so the answer never depends on scanning your whole event history.

GET /analytics/stats

from and to are required (ISO 8601; the window is inclusive on both ends, counted in UTC days). group_by is day (default), tag, type or domain. Optional filters: environment (live by default), tag, domain and type. Scope: analytics:read.

The response is { rows, totals }. Each row carries key plus the counters below; totals carries the same counters for the whole window.

CounterMeaning
sentAccepted by the provider — “did it leave?”
deliveredConfirmed delivered (partial deliveries included).
deferredTemporarily postponed; may still be delivered.
bouncedPermanently rejected, or accepted and undeliverable.
failedRejected, failed or expired before delivery.
suppressedRecipient was on the suppression list; nothing was sent.
complainedMarked as spam.
opened / opened_uniqueOpens: raw, and one per message.
clicked / clicked_uniqueClicks: raw, and one per message.
unsubscribedOpted out through the unsubscribe link.

How to read the numbers

Use opened_unique when you want an open rate: mailbox providers pre-load and re-load the tracking pixel, so the raw opened is higher than the number of people who read the message.

totals is not the sum of the rows when you group by tag or domain: a message with three tags appears in three rows and once in the total. Filter by tag or by domain, never both — one dimension at a time is what the rollup keeps, so asking for both is refused instead of answered with a wrong number.

The rollup is refreshed every few minutes, so a very recent send can appear in GET /email/events before it appears here. The window you may ask for is your plan’s retention: an older from is refused with the earliest date you can use, instead of silently returning an empty chart.