---
title: Statistics Reference
path: reference/stats
status: published
---

# Statistics Reference

Endpoints for daily, category-level, and summary statistics. Stats are aggregated nightly from message events; live sends are reflected the next day (or immediately, if you manually rebuild).

**Base path:** `/v3/stats/`
**Required permission:** `stats.read`.

## GET /v3/stats

Daily statistics for a date range.

**Query parameters:**

| Parameter | Type | Required | Notes |
|-----------|------|---------|-------|
| `start_date` | string (`YYYY-MM-DD`) | Yes | Inclusive |
| `end_date` | string (`YYYY-MM-DD`) | No | Inclusive; defaults to today |
| `aggregated_by` | string | No | `day` (default), `week`, `month` |

**Response (200):**

```json
{
  "stats": [
    {
      "date": "2026-04-23",
      "metrics": {
        "requests": 5000,
        "processed": 4998,
        "delivered": 4850,
        "bounces": 120,
        "bounce_drops": 4,
        "blocks": 3,
        "spam_reports": 2,
        "spam_report_drops": 0,
        "unsubscribes": 8,
        "unsubscribe_drops": 0,
        "invalid_emails": 0,
        "opens": 2400,
        "unique_opens": 2180,
        "clicks": 500,
        "unique_clicks": 390,
        "deferred": 50
      }
    }
  ]
}
```

## GET /v3/stats/categories

Statistics broken down by category (category tags on the original send).

**Query parameters:**

| Parameter | Required | Notes |
|-----------|---------|-------|
| `start_date` | Yes | |
| `end_date` | No | |
| `categories` | No | Comma-separated list; filter to just these |

**Response (200):**

```json
[
  {
    "date": "2026-04-23",
    "stats": [
      {"category": "onboarding", "metrics": {"delivered": 1200, ...}},
      {"category": "receipts", "metrics": {"delivered": 3650, ...}}
    ]
  }
]
```

## GET /v3/stats/summary

Single totals summary for a date range.

**Query parameters:** `start_date` (required), `end_date`.

**Response (200):**

```json
{
  "total_messages": 15234,
  "delivered": 14800,
  "bounced": 234,
  "opened": 7100,
  "clicked": 1420,
  "unsubscribed": 28,
  "spam_reports": 4,
  "delivery_rate": 0.971,
  "open_rate": 0.480,
  "click_rate": 0.096
}
```

## GET /v3/stats/sum

Raw sum of all metrics, no per-day breakdown.

**Query parameters:** `start_date` (required), `end_date`.

**Response (200):**

```json
{
  "blocks": 0,
  "bounce_drops": 12,
  "bounces": 234,
  "clicks": 1420,
  "deferred": 156,
  "delivered": 14800,
  "invalid_emails": 0,
  "opens": 7100,
  "processed": 15234,
  "requests": 15234,
  "spam_report_drops": 0,
  "spam_reports": 4,
  "unique_clicks": 1150,
  "unique_opens": 6400,
  "unsubscribe_drops": 0,
  "unsubscribes": 28
}
```

## POST /v3/stats/rebuild

Rebuild daily aggregates from the raw event log. Use after a bulk import of events, or if you suspect aggregation drift.

**Query parameters:** `start_date`, `end_date` (both optional; default to the last 30 days).

**Response (200):**

```json
{"message": "Rebuilt stats for 30 days", "days_rebuilt": 30}
```

Requires `stats.export` (this endpoint mutates aggregates).

## Metric definitions

| Metric | Definition |
|--------|------------|
| `requests` | `/v3/mail/send` calls counted per-personalization |
| `processed` | Messages accepted and queued by the worker |
| `delivered` | Messages accepted by recipient MX (`250 OK`) |
| `bounces` | Permanent failures (hard bounces + blocks) |
| `bounce_drops` | Messages dropped because recipient was on the bounce list |
| `blocks` | 5xx SMTP rejections specifically for reputation/policy |
| `spam_reports` | FBL complaints received |
| `spam_report_drops` | Messages dropped because recipient was on the spam-report list |
| `unsubscribes` | Global unsubscribe actions |
| `unsubscribe_drops` | Messages dropped because recipient was globally unsubscribed |
| `invalid_emails` | Malformed recipient addresses rejected at validation |
| `opens` | Tracking pixel loads (repeated opens counted) |
| `unique_opens` | Distinct recipients who opened at least once |
| `clicks` | Click redirect hits (repeated clicks counted) |
| `unique_clicks` | Distinct recipients who clicked at least one link |
| `deferred` | Temporary failures (4xx); these later become either `delivered` or `bounces` |

## What counts and what doesn't

- **Sandbox messages don't count** — stats ignore `SANDBOX` status.
- **Cancelled messages don't count** in `processed` — they never entered the worker pipeline.
- **Request-level failures (400) don't count** — stats start at the "message successfully queued" stage.

## Related

- [Messages Reference](messages) — per-message detail behind the aggregate.
- [Events and Webhooks](../concepts/events-and-webhooks) — the raw events that get aggregated.
