# Retrieve a campaign's metrics

Source: https://kirora.io/docs/api/reference/getCampaignMetrics

`GET /v1/campaigns/{id}/metrics`

Requires an API key with the `campaigns:read` scope. [About keys and scopes](https://kirora.io/docs/api/reference/authentication)

Works with integration, agent and partner keys.

Returns how a campaign did over its whole life. People-level numbers sit at the top: `recipientCount`, and the conversions and credited revenue its messages drove (gross, before refunds; zeros without conversion goals). Message counters sit under `email` and `push`, never added together, `null` for a channel the campaign does not send; push device outcomes are under `push.devices`. Email's `opened` includes machine opens (`openedByMachine`); a machine's click counts in neither `clicked` nor `opened`. Counters keep moving after a send completes, as opens, clicks and bounces arrive.

## Path parameters

- `id` (string, required, uuid) — The campaign's id.

## Header parameters

- `Kirora-Workspace` (string, optional, pattern `^[A-Za-z0-9._:-]{1,128}$`) — Partner keys only: the child workspace to act in, by the external id the partner gave it. Without it, a partner key acts in its own workspace. Any other key that sends it is refused with 403, and an unknown workspace is 404.

## Returns

Returns `200 OK` with a `CampaignMetrics` in `data`. Otherwise returns an error; [Errors](https://kirora.io/docs/api/reference/errors) lists every code and which to retry.

- `campaignId` (string, required, uuid)
- `recipientCount` (integer, required, min 0) — People the campaign went to, each counted once across channels.
- `conversions` (integer, required, min 0) — Conversions of the campaign's goals that its messages drove; 0 without goals.
- `revenue` (Money[], required) — Credited revenue per goal currency, never converted: what conversions a message drove were worth, gross, before refunds and cancellations.
  - `currency` (string | null, required) — The currency, an ISO 4217 code; null when none was named.
  - `value` (number, required) — The amount in that currency.
- `revenueWithheld` (boolean, required) — True when `revenue` leaves out the value of a goal whose value property is a masked attribute this viewer may not see; its conversions are still counted.
- `email` (object | null, required) — Email message counters; `null` when the campaign sends no email.
  - `queued` (integer, required, min 0) — Messages waiting to be sent.
  - `sending` (integer, required, min 0) — Messages being handed to the provider.
  - `skipped` (integer, required, min 0) — Messages not sent; see `skippedByReason`.
  - `sent` (integer, required, min 0) — Messages the provider accepted, whatever happened next: a delivered, bounced or failed message still counts here.
  - `failed` (integer, required, min 0) — Messages that could not be sent or failed after sending.
  - `delivered` (integer, required, min 0) — Messages confirmed delivered, including any later marked as spam.
  - `bounced` (integer, required, min 0) — Messages in status `bounced`, test sends to `bounce@example.com` included (see `simulated`); `deliverabilityHealth` counts recorded bounces of real sends only.
  - `complained` (integer, required, min 0) — Messages in status `complained`, test sends to `complaint@example.com` included (see `simulated`).
  - `opened` (integer, required, min 0) — Messages opened at least once.
  - `openedByMachine` (integer, required, min 0) — Of `opened`, those only a machine opened: a mail app fetched its images with no reader (Apple Mail Privacy Protection, Gmail's prefetch on delivery) or a mail security scanner checked it. Clicks are unaffected.
  - `clicked` (integer, required, min 0) — Messages with a link clicked at least once, by a person.
  - `clickedByMachine` (integer, required, min 0) — Messages whose links a machine followed: a mail security scanner checking them on delivery, a link preview. The machine's click counts in neither `clicked` nor `opened` (a person's click on the same message still does), and no webhook or journey sees it.
  - `unsubscribed` (integer, required, min 0) — Recipients who opted out through this campaign's link.
  - `simulated` (integer, required, min 0) — Test sends whose outcome was acted out: those to `delivered@`, `bounce@` or `complaint@example.com` (the transactional guide's "Test addresses"). These counts go by message status, so they include them; `deliverabilityHealth` leaves them out.
  - `total` (integer, required, min 0) — All messages created. `sent` and `delivered` overlap the other counts, so they do not add up to it; `byStatus` does.
  - `byStatus` (map<string, integer>, required, keys: one of `queued`, `sending`, `skipped`, `sent`, `failed`, `delivered`, `bounced`, `complained`, values: min 0) — Each message once, by where it is now, summing to `total`: the delivery breakdown. A delivered message later marked as spam is `complained` here, while `delivered` above still counts it.
- `deliverabilityHealth` (object | null, required) — Advisory bounce and complaint health of the campaign's email, judged on the same lines and minimums as `deliverabilityHealth` on `getOverviewReport`; `null` when the campaign sends no email. It reads real sends only: test sends (`email.simulated`) are left out, though `email.bounced` and `email.complained`, counted by status, include them.
  - `band` (string, required, one of `insufficient_data`, `healthy`, `watch`, `critical`) — `insufficient_data` until the sample and feedback coverage minimums are met; then the highest line the bounce or complaint ratio reaches.
  - `limits` (DeliverabilityLimits, required) — Where the bands start, the workspace's own lines: `watch` where its admins are warned, `critical` where its marketing email pauses. The pause is judged on all of the workspace's marketing email over the last 24 hours (or week, for a small sender), not on one report.
    - `watch` (object, required)
      - `bounceRatio` (number, required, min 0, max 1) — A ratio from 0 to 1: 0.05 is 5%.
      - `complaintRatio` (number, required, min 0, max 1) — A ratio from 0 to 1: 0.05 is 5%.
    - `critical` (object, required)
      - `bounceRatio` (number, required, min 0, max 1) — A ratio from 0 to 1: 0.05 is 5%.
      - `complaintRatio` (number, required, min 0, max 1) — A ratio from 0 to 1: 0.05 is 5%.
  - `bounceRatio` (number | null, required, min 0, max 1) — Recorded bounces per sent email, the figure the band compares with `limits`; `null` while `sampleSize` is 0.
  - `complaintRatio` (number | null, required, min 0, max 1) — Recorded complaints per sent email, the figure the band compares with `limits`; `null` while `sampleSize` is 0.
  - `sampleSize` (integer, required, min 0) — Sent emails the band is judged on: real sends only, with test sends that act an outcome out (`delivered@`, `bounce@`, `complaint@example.com`) left out.
  - `minimumSampleSize` (integer, required, min 1) — The fewest emails (`sampleSize`) the band is judged on, currently 100: below it the band is `insufficient_data`.
  - `feedbackCoverage` (number | null, required, min 0, max 1) — Share of the sample whose outcome (delivered, bounced or complained) is known; `null` before any email is sent.
  - `minimumFeedbackCoverage` (number, required, min 0, max 1) — The least `feedbackCoverage` the band is judged on, currently 0.95: below it the band is `insufficient_data`, as bounce and complaint reports are still arriving.
- `push` (object | null, required) — Push message counters; `null` when the campaign sends no push.
  - `queued` (integer, required, min 0) — Messages waiting to be sent.
  - `sending` (integer, required, min 0) — Messages being handed to the provider.
  - `skipped` (integer, required, min 0) — Messages not sent; see `skippedByReason`.
  - `sent` (integer, required, min 0) — Messages the provider accepted, whatever happened next: a delivered, bounced or failed message still counts here.
  - `failed` (integer, required, min 0) — Messages that could not be sent or failed after sending.
  - `byStatus` (object, required) — Each message once, by where it is now, summing to `total`.
    - `queued` (integer, required, min 0)
    - `sending` (integer, required, min 0)
    - `skipped` (integer, required, min 0)
    - `sent` (integer, required, min 0)
    - `failed` (integer, required, min 0)
  - `opened` (integer, required, min 0) — Messages the app reported opened at least once.
  - `clicked` (integer, required, min 0) — Messages the app reported tapped through to a link at least once.
  - `total` (integer, required, min 0) — All messages created.
  - `devices` (object, required) — Device outcomes: one push message goes to every device its contact has, so these count devices, not messages, and never add to the counters beside them.
    - `pending` (integer, required, min 0) — Devices not yet attempted.
    - `started` (integer, required, min 0) — Devices being sent to now.
    - `accepted` (integer, required, min 0) — Devices the push service accepted.
    - `invalid` (integer, required, min 0) — Devices whose registration is no longer valid.
    - `rejected` (integer, required, min 0) — Devices the push service permanently refused.
    - `retryable` (integer, required, min 0) — Devices that failed temporarily and will be retried.
    - `unknown` (integer, required, min 0) — Devices whose outcome could not be determined.
    - `skipped` (integer, required, min 0) — Devices not sent to.
    - `total` (integer, required, min 0) — All devices targeted.
    - `byPlatform` (object, required)
      - `ios` (object, optional)
        - `pending` (integer, required, min 0) — Devices not yet attempted.
        - `started` (integer, required, min 0) — Devices being sent to now.
        - `accepted` (integer, required, min 0) — Devices the push service accepted.
        - `invalid` (integer, required, min 0) — Devices whose registration is no longer valid.
        - `rejected` (integer, required, min 0) — Devices the push service permanently refused.
        - `retryable` (integer, required, min 0) — Devices that failed temporarily and will be retried.
        - `unknown` (integer, required, min 0) — Devices whose outcome could not be determined.
        - `skipped` (integer, required, min 0) — Devices not sent to.
        - `total` (integer, required, min 0) — All devices targeted.
      - `android` (object, optional)
        - `pending` (integer, required, min 0) — Devices not yet attempted.
        - `started` (integer, required, min 0) — Devices being sent to now.
        - `accepted` (integer, required, min 0) — Devices the push service accepted.
        - `invalid` (integer, required, min 0) — Devices whose registration is no longer valid.
        - `rejected` (integer, required, min 0) — Devices the push service permanently refused.
        - `retryable` (integer, required, min 0) — Devices that failed temporarily and will be retried.
        - `unknown` (integer, required, min 0) — Devices whose outcome could not be determined.
        - `skipped` (integer, required, min 0) — Devices not sent to.
        - `total` (integer, required, min 0) — All devices targeted.
      - `web` (object, optional)
        - `pending` (integer, required, min 0) — Devices not yet attempted.
        - `started` (integer, required, min 0) — Devices being sent to now.
        - `accepted` (integer, required, min 0) — Devices the push service accepted.
        - `invalid` (integer, required, min 0) — Devices whose registration is no longer valid.
        - `rejected` (integer, required, min 0) — Devices the push service permanently refused.
        - `retryable` (integer, required, min 0) — Devices that failed temporarily and will be retried.
        - `unknown` (integer, required, min 0) — Devices whose outcome could not be determined.
        - `skipped` (integer, required, min 0) — Devices not sent to.
        - `total` (integer, required, min 0) — All devices targeted.
- `skippedByReason` (map<string, integer>, required, values: min 0) — Skipped messages by reason, such as `message_limit` or `expired`, across channels; each channel's `skipped` is its part.
- `abTest` (object | null, required) — The test group's results by version; the rest of the audience is in the totals only. `null` without an A/B test.
  - `winner` (integer | null, required, min 1) — The winning version, once picked.
  - `versions` (AbTestVersionResult[], required) — Each version in the test group, version 1 first. The winner is picked on open and click rates over `delivered` (over `sent` until any version has a delivery) and conversions over `sent`.
    - `version` (integer, required, min 1)
    - `sent` (integer, required, min 0) — Test messages handed to the provider.
    - `delivered` (integer, required, min 0)
    - `opened` (integer, required, min 0) — Test messages a person opened; machine opens are left out.
    - `clicked` (integer, required, min 0)
    - `conversions` (integer, required, min 0) — Recipients who reached the test's conversion goal; 0 without one.

## Example

```bash
curl https://api.kirora.io/v1/campaigns/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b/metrics \
  -H "Authorization: Bearer $KIRORA_API_KEY"
```

Response `200`:

```json
{
  "data": {
    "campaignId": "0192f3d3-5e6f-7071-8c83-9e0f1a2b3c4d",
    "recipientCount": 2455,
    "conversions": 41,
    "revenue": [
      {
        "currency": "USD",
        "value": 2870.5
      }
    ],
    "revenueWithheld": false,
    "email": {
      "queued": 0,
      "sending": 0,
      "skipped": 12,
      "sent": 2440,
      "failed": 3,
      "delivered": 2391,
      "bounced": 38,
      "complained": 2,
      "opened": 1130,
      "openedByMachine": 412,
      "clicked": 341,
      "clickedByMachine": 29,
      "unsubscribed": 6,
      "simulated": 0,
      "total": 2455,
      "byStatus": {
        "queued": 0,
        "sending": 0,
        "skipped": 12,
        "sent": 11,
        "failed": 3,
        "delivered": 2389,
        "bounced": 38,
        "complained": 2
      }
    },
    "deliverabilityHealth": {
      "band": "healthy",
      "limits": {
        "watch": {
          "bounceRatio": 0.02,
          "complaintRatio": 0.0005
        },
        "critical": {
          "bounceRatio": 0.03,
          "complaintRatio": 0.0008
        }
      },
      "bounceRatio": 0.004,
      "complaintRatio": 0,
      "sampleSize": 2455,
      "minimumSampleSize": 100,
      "feedbackCoverage": 0.99,
      "minimumFeedbackCoverage": 0.95
    },
    "push": null,
    "skippedByReason": {
      "message_limit": 12
    },
    "abTest": null
  }
}
```
