# Metrics

Delivery, bounce, complaint and engagement counts for the account, over a date range you choose and broken down however you ask.

## Freshness

Data is updated every minute.

Counts are rolled up into one-minute buckets. The response carries `data_as_of`, the end of the last completed bucket, and `end_date` is clamped down to it — so a range never reports a partly-filled window as though it were final, and a message sent seconds ago is not yet in these numbers.

> Rates are fractions between 0 and 1, not percentages. A `bounce_rate` of `0.03` is 3%.

## The metrics

| Metric | Means |
| --- | --- |
| `received` | Inbound messages your receiving addresses kept. |
| `delivered` | Messages a receiving mail server accepted. |
| `complained` | Messages a recipient reported as spam. |
| `suppressed` | Sends skipped because the address was on your suppression list. |
| `bounced` | Messages that bounced, of any kind. |
| `bounced_transient` | Bounces the receiver called temporary — a full mailbox, a rejected size. |
| `bounced_permanent` | Bounces the receiver called permanent. These add the address to suppressions. |
| `bounced_undetermined` | Bounces the receiver did not call permanent or temporary. |
| `opened` | Opens recorded, counting the same reader more than once. |
| `clicked` | Clicks recorded, counting the same reader more than once. |
| `delivery_delayed` | Messages a receiver deferred and has not yet accepted or rejected. |
| `failed` | Messages we could not submit, or that were rejected before sending. |
| `sent` | Messages handed to the mail provider. |
| `unique_opened` | Recipients who opened, each counted once. |
| `unique_clicked` | Recipients who clicked, each counted once. |
| `delivery_rate` | delivered ÷ sent. |
| `open_rate` | opened ÷ delivered. |
| `click_rate` | clicked ÷ delivered. |
| `bounce_rate` | bounced ÷ sent. |
| `complaint_rate` | complained ÷ sent. |
| `attempted` | Emails that were sent, failed or suppressed. Each email counts once, even with several outcomes. |

Ask for a subset with `metrics`, comma-separated or repeated. Every metric above is counted from your mail. A name that is not in this table is refused with `422 invalid_parameter`.

## Breaking the totals down

| Dimension | Means |
| --- | --- |
| `period` | One row per time bucket, at the requested granularity. |
| `domain` | One row per sending domain. |
| `email` | One row per email. Cannot be combined with `broadcast`. |
| `broadcast` | One row per broadcast. Marketing sends only. Cannot be combined with `email`. |

- `totals` is always present. `data` is omitted entirely when you ask for no dimensions — it is absent, not an empty array.
- With `period`, `granularity` chooses the bucket width: `hourly`, `daily`, `weekly` or `monthly`. It defaults to `daily`.

## Endpoints

### `GET /emails/metrics`

Delivery, bounce, complaint and engagement counts for the account.

#### Query parameters

| Field | Type | Description |
| --- | --- | --- |
| `start_date` | string | ISO 8601 date or datetime. Defaults to six days before `end_date`. |
| `end_date` | string | ISO 8601 date or datetime. A value in the future is clamped to now, and then down to the last completed one-minute bucket. |
| `metrics` | string | Comma-separated, repeated, or both. Defaults to every metric. Rate metrics are fractions between 0 and 1. |
| `dimensions` | string | `period`, `domain`, `email` or `broadcast`. `data` is omitted entirely when this is empty. `email` cannot be combined with `broadcast`. |

#### Query parameters, less common

| Field | Type | Description |
| --- | --- | --- |
| `granularity` | string | `hourly`, `daily`, `weekly` or `monthly`. Defaults to `daily`. |
| `domain_id` | string | Restrict to one or more domains, comma-separated. Up to 100 ids. |
| `email_id` | string | Restrict to one or more emails, comma-separated. Up to 100 ids. |
| `broadcast_id` | string | Restrict to one or more broadcasts (campaigns), comma-separated. Up to 100 ids. |
| `timezone` | string | IANA timezone name. Defaults to `UTC`. |

Retrieve metrics:

```sh
curl -X GET "https://api.rasket.com/emails/metrics?metrics=sent%2Cdelivered%2Cbounce_rate&dimensions=period" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"
```

```ts
const response = await fetch("https://api.rasket.com/emails/metrics?metrics=sent%2Cdelivered%2Cbounce_rate&dimensions=period", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
    "User-Agent": "acme-billing/1.0",
  },
});

const data = await response.json();
```

```python
import os

import requests

response = requests.get(
    "https://api.rasket.com/emails/metrics?metrics=sent%2Cdelivered%2Cbounce_rate&dimensions=period",
    headers={
        "Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
        "User-Agent": "acme-billing/1.0",
    },
)

print(response.json())
```

#### Response `200`

```json
{
  "object": "metrics",
  "start_date": "2026-09-02T00:00:00.000Z",
  "end_date": "2026-09-09T14:30:00.000Z",
  "metrics": ["sent", "delivered", "bounce_rate"],
  "dimensions": ["period"],
  "granularity": "daily",
  "totals": {
    "sent": 1000,
    "delivered": 960,
    "bounce_rate": 0.03
  },
  "data_as_of": "2026-09-09T14:30:00.000Z",
  "data": [
    {
      "period": "2026-09-09",
      "sent": 140,
      "delivered": 135,
      "bounce_rate": 0.028
    }
  ]
}
```

- Rate metrics are fractions, not percentages: a `bounce_rate` of `0.03` is 3%.
- Totals are aggregated in one-minute buckets. `data_as_of` is the end of the last completed bucket, and `end_date` is clamped down to it, so a range never reports a partly-filled window as a final one.
- `data` is omitted rather than empty when `dimensions` is empty.
- A metric this release does not aggregate yet answers `0` rather than being absent, so a caller can index the object it expects.
