Skip to main content

Analytics

Two endpoints: totals for a range, and the same numbers bucketed over time.

curl "https://api.epostix.com/v1/analytics/summary?start=2026-08-01T00:00:00Z&end=2026-09-01T00:00:00Z" \
-H "Authorization: Bearer $EPOSTIX_API_KEY"
{
"start": "2026-08-01T00:00:00Z",
"end": "2026-09-01T00:00:00Z",
"as_of": "2026-08-19T14:52:00Z",
"counts": {
"accepted": 48210,
"delivered": 47655,
"failed": 555,
"bounced": 412,
"unique_opens": 21044,
"unique_clicks": 3180,
"raw_opens": 33901,
"raw_clicks": 4522,
"machine_opens": 9877,
"apple_mpp_opens": 7401
}
}

Counts, never rates

We return counts and leave the arithmetic to you. That is deliberate: an open rate over delivered and an open rate over accepted are different numbers, and a rate we picked for you would hide which one you were reading.

Compute the rate you actually want, and the denominator is then explicit in your own code.

What each count means

Three of these are easy to misread, so they are worth stating plainly.

accepted is not "sent". It counts messages we accepted for delivery. A message can be accepted and then fail, so accepted is the top of the funnel rather than a success measure.

bounced is a subset of failed, not an addition to it. Adding them double-counts. failed is every message that did not arrive; bounced is the portion that failed because the receiving server rejected the address.

unique_opens is the first qualifying open per message, with scanner and privacy-proxy opens excluded. That is almost always the number you want. raw_opens counts every open event, and machine_opens counts the ones we attributed to a machine rather than a person, including apple_mpp_opens. Very few providers will tell you that number at all.

Over time

curl "https://api.epostix.com/v1/analytics/timeseries?start=2026-08-01T00:00:00Z&end=2026-08-08T00:00:00Z&interval=hour" \
-H "Authorization: Bearer $EPOSTIX_API_KEY"

interval is hour or day, and buckets are UTC. A range longer than 7 days with hour, or 92 days with day, is rejected with validation_error rather than quietly truncated.

Two bucketings share one response, and the difference matters. accepted, delivered and failed are bucketed by when the message was accepted. bounced, opens and clicks are bucketed by when the event happened. A message accepted on Monday that bounces on Tuesday counts in Monday's accepted and Tuesday's bounced, so in any single bucket bounced can exceed failed. Over a wide enough range they reconcile.

Freshness

as_of is when the underlying aggregate was last reconciled, and it is on every response. Numbers are typically a minute behind. Deliveries that settle long after acceptance, such as a message deferred and retried by the receiving server, take longer to land.

Read as_of rather than assuming the numbers are current, particularly if you are drawing a dashboard that refreshes on a timer.

Test sends are excluded

Nothing sent with a tix_test_ key or to a sandbox address appears here. Analytics describes production only.

Filtering

purpose narrows to transactional or marketing. The default, all, sums both, which is rarely what you want when comparing periods: a campaign in one period and not the other will dominate the difference.