# List campaign reports

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

`GET /v1/reports/campaigns`

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

Works with integration, agent and partner keys.

Available on plans with advanced reports. [Plans](https://kirora.io/pricing)

Lists campaign performance over a window. One row per campaign with a marketing message in the window, including a campaign none of whose messages were sent: its email shows as `failed` or `skipped`. Counts are send cohorts like the overview: email by the time it was sent, email never sent and push by the time it was queued, and later feedback revises them. Journey and transactional messages are not here (see the journey and transactional reports), so these rows can sum to less than the overview. Conversions are those whose source message was sent in the window, and revenue is summed per goal currency, never converted. Rates are fractions; null means no denominator, and sorts below every rate. `sent` sorts by email sent. Without `from` and `to`, the window is the last 30 days ending today. Needs a plan with advanced reports: without one, 403 `PLAN_FEATURE_UNAVAILABLE`.

## Query parameters

- `limit` (integer, optional, min > 0, max 100, default `20`) — How many items a page holds: 1 to 100, 20 by default.
- `cursor` (string, optional, 1–2,048 characters) — Where the page starts: the previous page's `meta.pagination.nextCursor`. Omit it for the first page, and send the same filters with it.
- `from` (string, optional) — Start of the window, inclusive: a date-time, or a date meaning the start of that day in the workspace timezone. Give with `to`; omit both for the last 30 days.
- `to` (string, optional) — End of the window, exclusive, in the same forms. To include a whole last day, pass the day after it: `from=2026-10-01&to=2026-10-08` covers 1 to 7 October. No later than the end of today; a window touches at most 366 days. Give with `from`.
- `sort` (string, optional, one of `firstAttemptedAt`, `sent`, `openRate`, `clickRate`, `bounceRate`, `unsubscribeRate`, `conversions`, `-firstAttemptedAt`, `-sent`, `-openRate`, `-clickRate`, `-bounceRate`, `-unsubscribeRate`, `-conversions`, default `"-firstAttemptedAt"`) — A field ascending, or `-field` descending. Rates with no denominator sort last.
- `tag` (string, optional, 1–64 characters) — Only campaigns carrying this tag, its name matched without case: "everything tagged Black Friday".

## 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 list of `CampaignPerformance` objects in `data`, and the next page's cursor in `meta` (see [pagination](https://kirora.io/docs/api/reference/pagination)). Otherwise returns an error; [Errors](https://kirora.io/docs/api/reference/errors) lists every code and which to retry.

- `campaignId` (string, required, uuid)
- `name` (string, required)
- `status` (string, required, one of `draft`, `scheduled`, `sending`, `testing`, `sent`, `cancelled`)
- `channels` (string[], required) — The channels the campaign targets.
- `firstAttemptedAt` (string, required, date-time) — The campaign's first message in the window: when it was sent, or queued for one never sent. Not the campaign schedule.
- `email` (object, required) — Email counts and rates for the window. `sent` covers only email the provider accepted.
  - `sent` (integer, required, min 0)
  - `delivered` (integer, required, min 0)
  - `opened` (integer, required, min 0) — Opened at least once, including `openedByMachine`.
  - `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.
  - `clicked` (integer, required, min 0) — With a link clicked by a person.
  - `failed` (integer, required, min 0) — Not delivered, with no bounce or complaint: refused before sending, or failed after it. Each message's `failure.reason` says why.
  - `skipped` (integer, required, min 0) — Stopped before sending by a guard (no consent, suppressed, no address). Not in `sent`.
  - `bounced` (integer, required, min 0)
  - `complained` (integer, required, min 0)
  - `unsubscribed` (integer, required, min 0)
  - `rates` (EmailRates, required) — Email rates as fractions: delivery over sent; bounce and complaint over real sends (`sent` less `simulated` where the counts give it), as `deliverabilityHealth` judges them; open, click and unsubscribe over delivered. `null` when there is no denominator.
    - `delivery` (number | null, required, min 0)
    - `open` (number | null, required, min 0)
    - `click` (number | null, required, min 0)
    - `bounce` (number | null, required, min 0)
    - `complaint` (number | null, required, min 0)
    - `unsubscribe` (number | null, required, min 0)
- `push` (object, required) — Push counts for the window.
  - `sent` (integer, required, min 0)
  - `failed` (integer, required, min 0)
  - `opened` (integer, required, min 0)
  - `clicked` (integer, required, min 0)
- `conversions` (integer, required, min 0) — Goal conversions whose source message was sent in the window.
- `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.

## Example

```bash
curl https://api.kirora.io/v1/reports/campaigns \
  -H "Authorization: Bearer $KIRORA_API_KEY"
```

Response `200`:

```json
{
  "data": [
    {
      "campaignId": "0192f3d3-5e6f-7071-8c83-9e0f1a2b3c4d",
      "name": "October newsletter",
      "status": "sent",
      "channels": [
        "email"
      ],
      "firstAttemptedAt": "2026-10-01T09:31:00.000Z",
      "email": {
        "sent": 1000,
        "delivered": 980,
        "opened": 410,
        "openedByMachine": 120,
        "clicked": 96,
        "failed": 3,
        "skipped": 20,
        "bounced": 12,
        "complained": 1,
        "unsubscribed": 6,
        "rates": {
          "delivery": 0.98,
          "open": 0.418,
          "click": 0.098,
          "bounce": 0.012,
          "complaint": 0.001,
          "unsubscribe": 0.006
        }
      },
      "push": {
        "sent": 0,
        "failed": 0,
        "opened": 0,
        "clicked": 0
      },
      "conversions": 21,
      "revenue": [
        {
          "currency": "USD",
          "value": 964.5
        }
      ],
      "revenueWithheld": false
    }
  ],
  "meta": {
    "pagination": {
      "limit": 20,
      "nextCursor": null
    },
    "window": {
      "from": "2026-09-07T23:00:00.000Z",
      "to": "2026-10-07T23:00:00.000Z",
      "timezone": "Europe/London"
    }
  }
}
```
