Analytics: Summary & Timeseries
Get email delivery and engagement metrics
Use analytics endpoints to understand email performance across your campaigns and flows.
Summary Metrics
Get aggregate metrics for a time period.
cURL
curl "https://api.tratto.email/v1/analytics/summary?period=30d" \
-H "Authorization: Bearer tratto_live_..."Query Parameters:
period: Time range —7d,30d,90d(default30d),180d, or1y
Response:
{
"data": {
"period": "30d",
"totalSent": 50000,
"delivered": 49500,
"opened": 24750,
"clicked": 7425,
"bounced": 400,
"complained": 100,
"deliveryRate": 99,
"openRate": 50,
"clickRate": 15,
"bounceRate": 0.8,
"avgDeliveryLatencySeconds": 4.2
}
}Metric Definitions
| Metric | Definition |
|---|---|
totalSent | Emails sent to mail server |
delivered | Mail servers confirmed delivery (no bounce) |
opened | Unique recipients who opened email |
clicked | Unique recipients who clicked a link |
bounced | Mail servers rejected delivery (hard or soft bounce) |
complained | Recipients marked as spam |
avgDeliveryLatencySeconds | Average time from send to delivery confirmation. null when no email in the period has been delivered yet |
unsubscribed isn't part of this endpoint — it's tracked on the contact, not on individual emails. Check a contact's status instead. A campaign has no unsubscribed count either — the nearest thing is stats.skipped, the sends cancelled because the contact unsubscribed between dispatch and delivery (see Campaigns).
Rates
All rates are percentages (98.5 means 98.5%, not 0.985).
| Rate | Calculation |
|---|---|
deliveryRate | delivered / totalSent |
openRate | opened / delivered (falls back to totalSent if nothing delivered yet) |
clickRate | clicked / opened (falls back to totalSent) |
bounceRate | bounced / totalSent |
These are workspace-wide rates. For one campaign, including the per-subject results of an A/B subject test, use GET /v1/campaigns/:id/stats: its open and click rates leave out recipients who opted out of tracking.
Timeseries Data
Get daily breakdown of metrics.
cURL
curl "https://api.tratto.email/v1/analytics/timeseries?period=7d" \
-H "Authorization: Bearer tratto_live_..."Response:
{
"data": [
{
"date": "2026-07-30",
"sent": 5000,
"delivered": 4950,
"opened": 2475,
"bounced": 40
},
{
"date": "2026-07-29",
"sent": 4800,
"delivered": 4752,
"opened": 2376,
"bounced": 38
}
]
}Note the narrower shape than the summary endpoint: sent/delivered/opened/bounced only, no clicked or complained per day.
Top Clicked Links
Get the most-clicked links for a specific campaign.
cURL
curl "https://api.tratto.email/v1/campaigns/camp_abc123/links?limit=20" \
-H "Authorization: Bearer tratto_live_..."Response:
{
"data": [
{ "linkUrl": "https://example.com/pricing", "clicks": 142, "uniqueClicks": 98 },
{ "linkUrl": "https://example.com/docs", "clicks": 37, "uniqueClicks": 30 }
]
}limit is optional, 1-50, defaults to 20.
Live and Test Data
Analytics follow the environment of the key that asks. A tratto_live_... key
reads live sends only, a tratto_test_... key reads test
sends only.
Both endpoints also accept a livemode query parameter (true or false).
It is the view switch of the dashboard and is ignored for API keys: the
key's own environment always wins, so a live key cannot read test numbers and
a test key cannot read live ones, whatever you pass.
The test view is limited to 7d, 30d and 90d. The longer periods read an
aggregate that contains live data only, so a test key asking for 180d or
1y gets 422 VALIDATION_ERROR instead of zeros:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Analytics for the test environment are not available for the '180d' period.",
"docs": "https://docs.tratto.email/en/docs/error-codes",
"suggestion": "Periods longer than 90 days read the long-term aggregate, which contains live data only. Use period=90d or shorter for the test view."
}
}Data Windows: Firestore vs BigQuery
7d/30d/90dare served from Firestore in real time — no aggregation delay, but Firestore only retains email documents for 90 days.180d/1yare served from a nightly BigQuery aggregate instead. That aggregation runs once per day (around 02:30 UTC) — very recent data (today, and sometimes yesterday depending on when you check) won't be reflected yet for these two longer windows. Use90dor shorter if you need same-day numbers.
Best Practices
1. Monitor Delivery Rate
Target 99%+. Lower rates indicate domain or list hygiene issues.
if (data.deliveryRate < 95) {
alert('Low delivery rate detected');
}2. Track Open & Click Rates
Typical benchmarks:
- Open rate: 20-50% (varies by industry)
- Click rate: 5-20% (varies by industry)
Low rates suggest content or timing issues.
3. Monitor Bounce & Complaint Rates
- Bounce rate: < 2% acceptable (< 5% is OK)
- Complaint rate:
complained / totalSent— keep it under 0.1%
High rates damage sender reputation and deliverability.
Next Steps
- View email-level events? Use Email Status API
- Track real-time events? Set up Webhooks
- Understand deliverability? See Deliverability
Edit this page on GitHub
Last updated on