# Retrieve metrics

> Sent, delivered, bounces, complaints, opens, clicks and their rates over a range of UTC days, by day or broken down by domain, tag, template, broadcast or…

Source: https://docs.pidgely.com/api-reference/metrics/retrieve/

`GET https://api.pidgely.com/metrics`

Sent, delivered, bounces, complaints, opens, clicks and their rates over a range of UTC days, by day or broken down by domain, tag, template, broadcast or mailbox provider. Read from rollups the event pipeline keeps up to date, so the cost is the same for ten emails or ten million. See [Metrics](https://docs.pidgely.com/guides/metrics/) for every definition.

Pidgely extension. Counters and rates over a UTC day range (default the last 30 days, at most 400), read from rollups the event pipeline keeps up to date. `group_by=day` (default) returns one point per day; `domain`, `tag`, `template`, `broadcast` (alias `campaign`) and `provider` (recipient mailbox provider: gmail, outlook, yahoo, icloud, other) return one point per value, most sent first. One filter (`domain_id`, `tag`, `template_id`, `broadcast_id` or `provider`) narrows the result to that value, by day. Rates: `delivery_rate` = delivered / sent; `bounce_rate` = hard bounces / (delivered + hard bounces); `complaint_rate` = complaints / delivered; `open_rate` = unique human opens / delivered; `raw_open_rate` includes machine opens (Apple Mail Privacy Protection, image proxy prefetch); `click_rate` = unique human clicks / delivered; `click_to_open_rate` = unique human clicks / unique human opens. A rate is null when its denominator is 0. `alerts` warns above the mailbox providers' thresholds (4% bounces, 0.08% complaints) and is `critical` above the reputation guard's pause limits. Requires a `full_access` key.

**Authorization:** `Bearer pdg_…`. An API key with `full_access`. A `sending_access` key gets `401 restricted_api_key`.

## Query parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `days` | integer | No | Last N UTC days, today included (default 30). Ignored when `from` is set. Between 1 and 400. |
| `from` | string | No | First UTC day (YYYY-MM-DD). Format: `date`. |
| `to` | string | No | Last UTC day (YYYY-MM-DD, default today). Format: `date`. |
| `group_by` | string | No | `day` (default) or a dimension (one point per value). A filtered query is grouped by day. One of `day`, `domain`, `tag`, `template`, `broadcast`, `campaign`, `provider`. |
| `domain_id` | string | No | Only this sending domain. UUID. |
| `tag` | string | No | Only e-mails with this tag, as `name:value`. |
| `template_id` | string | No | Only e-mails sent from this template. UUID. |
| `broadcast_id` | string | No | Only this broadcast (campaign). UUID. |
| `provider` | string | No | Only recipients at this mailbox provider. One of `gmail`, `outlook`, `yahoo`, `icloud`, `other`. |

## Request

This endpoint is not in the [SDKs](https://docs.pidgely.com/sdks/) yet; call it over HTTP.

```bash tab="cURL"
curl -X GET 'https://api.pidgely.com/metrics?days=30&group_by=day' \
  -H "Authorization: Bearer $PIDGELY_API_KEY"
```

## Response

`200 OK`

```json
{
  "object": "metrics",
  "from": "2026-09-21",
  "to": "2026-10-20",
  "group_by": "day",
  "filter": null,
  "totals": {
    "key": "total",
    "sent": 1200,
    "delivered": 1188,
    "hard_bounced": 7,
    "soft_bounced": 5,
    "complained": 0,
    "delayed": 14,
    "suppressed": 3,
    "failed": 0,
    "unsubscribed": 4,
    "opens": 1630,
    "machine_opens": 402,
    "unique_opens": 702,
    "unique_human_opens": 455,
    "clicks": 233,
    "bot_clicks": 41,
    "unique_clicks": 160,
    "unique_human_clicks": 131,
    "delivery_rate": 0.99,
    "bounce_rate": 0.0059,
    "soft_bounce_rate": 0.0042,
    "complaint_rate": 0,
    "open_rate": 0.383,
    "raw_open_rate": 0.591,
    "click_rate": 0.1103,
    "click_to_open_rate": 0.2879,
    "unsubscribe_rate": 0.0034
  },
  "data": [
    {
      "key": "2026-10-20",
      "sent": 1200,
      "delivered": 1188,
      "hard_bounced": 7,
      "soft_bounced": 5,
      "complained": 0,
      "delayed": 14,
      "suppressed": 3,
      "failed": 0,
      "unsubscribed": 4,
      "opens": 1630,
      "machine_opens": 402,
      "unique_opens": 702,
      "unique_human_opens": 455,
      "clicks": 233,
      "bot_clicks": 41,
      "unique_clicks": 160,
      "unique_human_clicks": 131,
      "delivery_rate": 0.99,
      "bounce_rate": 0.0059,
      "soft_bounce_rate": 0.0042,
      "complaint_rate": 0,
      "open_rate": 0.383,
      "raw_open_rate": 0.591,
      "click_rate": 0.1103,
      "click_to_open_rate": 0.2879,
      "unsubscribe_rate": 0.0034
    }
  ],
  "alerts": [],
  "thresholds": {
    "bounce_rate_warning": 0.04,
    "complaint_rate_warning": 0.0008,
    "bounce_rate_limit": 0.04,
    "complaint_rate_limit": 0.001
  }
}
```

### Response fields

| Name | Type | Required | Description |
|---|---|---|---|
| `object` | string | Yes | Object type. One of `metrics`. |
| `from` | string | Yes | Format: `date`. |
| `to` | string | Yes | Recipient address (`a@x.com` or `Name <a@x.com>`) or a list of them. Up to 50 unique recipients across `to`, `cc` and `bcc`. Format: `date`. |
| `group_by` | string | Yes | — |
| `filter` | object \| null | Yes | — |
| `totals` | object | Yes | — |
| `data` | object[] | Yes | Items of this page. |
| `alerts` | object[] | Yes | — |
| `alerts[].metric` | string | Yes | One of `bounce_rate`, `complaint_rate`. |
| `alerts[].level` | string | Yes | One of `warning`, `critical`. |
| `alerts[].rate` | number | Yes | — |
| `alerts[].threshold` | number | Yes | — |
| `thresholds` | object | Yes | — |
| `thresholds.bounce_rate_warning` | number | Yes | — |
| `thresholds.complaint_rate_warning` | number | Yes | — |
| `thresholds.bounce_rate_limit` | number | Yes | The reputation guard pauses sending above this bounce rate (7-day window). |
| `thresholds.complaint_rate_limit` | number | Yes | The reputation guard pauses sending above this complaint rate (7-day window). |

## Errors

Errors have the shape `{"statusCode", "name", "message"}`. See [Errors](https://docs.pidgely.com/errors/) for the full list.

| Status | Name | When |
|---|---|---|
| 401 | `missing_api_key`, `restricted_api_key` | No `Authorization: Bearer` header, or a `sending_access` key called an endpoint that needs `full_access`. |
| 403 | `invalid_api_key`, `validation_error` | The API key is invalid or revoked, or the request is not allowed for this account (unverified domain, plan limit, paused account). |
| 422 | `validation_error` | A field is missing or invalid; `message` names it. |
| 429 | `rate_limit_exceeded` | Too many requests per second. Wait for `Retry-After` seconds. |
| 422 | `validation_error` | Unknown `group_by`, more than one filter, a filtered query not grouped by day, or a range over 400 days. |
