Campaign dashboard metrics

Overview

Get aggregated email/SMS campaign performance stats and audience contact counts for the authenticated user's company over a given date range, optionally scoped to one store.

Prerequisites

  • A bearer token. Callable with Account tokens.
  • Values for the required query parameters start_date, end_date — see the table below.

Base URL

EnvironmentURL
Productionhttps://production-api.shoutaboutus.com
Developmenthttps://development-api.shoutaboutus.com

Endpoint

GET /api/v1/campaign/dashboard/metrics

Authentication

  • Requires a bearer token in the Authorization: Bearer <bearer-token> header.

  • Who can call it: Account tokens.

  • Inside the authenticated api. group; the route lives under the campaign/dashboard account group.

  • Scope is implicit: the controller filters RsCampaign, so a caller only ever sees their own company's campaigns.

  • An optional store_id is further validated by an ownership check.

Rate limit

  • No rate limit.

Query parameters

  • Query: start_date (string Y-m-d, required) — start of the metrics window; parsed with startOfDay.
  • Query: end_date (string Y-m-d, required) — end of the window; must be after_or_equal:start_date; parsed with endOfDay.
  • Query: store_id (integer, optional / nullable) — scope metrics to a single store; must belong to the auth user's company hierarchy (an ownership check).

Response

  • data.status (string) — literal "success".
  • data.data.email_performance.sent (int) — non-test emails with sent_at in range.
  • data.data.email_performance.delivered (int) — emails with delivered_at in range.
  • data.data.email_performance.opened (int) — emails with opened_at in range.
  • data.data.email_performance.clicked (int) — emails with clicked_at in range.
  • data.data.email_performance.unsubscribed (int) — emails with unsubscribed_at in range.
  • data.data.email_performance.rates.delivered (float) — delivered / sent * 100, rounded 2dp (0 when sent=0).
  • data.data.email_performance.rates.opened (float) — opened / sent * 100.
  • data.data.email_performance.rates.clicked (float) — clicked / sent * 100.
  • data.data.email_performance.rates.unsubscribed (float) — unsubscribed / sent * 100.
  • data.data.email_performance.rates.sent (float) — sent / currentEmailValidContacts * 100 (denominator = audience rows in range with is_email_valid = valid).
  • data.data.sms_performance.sent (int) — non-test SMS with sent_at in range.
  • data.data.sms_performance.delivered (int) — SMS with delivered_at in range.
  • data.data.sms_performance.link_clicked (int) — SMS with link_clicked_at in range.
  • data.data.sms_performance.failed (int) — SMS where status = failed OR failed_at set, with the failure/send/creation timestamp in range.
  • data.data.sms_performance.rates.delivered (float) — delivered / sent * 100.
  • data.data.sms_performance.rates.link_clicked (float) — link_clicked / sent * 100.
  • data.data.sms_performance.rates.failed (float) — failed / sent * 100.
  • data.data.sms_performance.rates.sent (float) — sent / currentSmsValidContacts * 100 (denominator = audience rows in range with is_phone_valid = valid).
  • data.data.audience.current_contacts (int) — valid, non-test CampaignAudienceData rows created within the window.
  • data.data.audience.previous_contacts (int) — same count over the immediately preceding window of equal length.
  • data.data.audience.change_percent (float) — (current - previous) / previous * 100, rounded 2dp (0 when previous=0).

200 OK · 200

{
  "data": {
    "status": "success",
    "data": {
      "email_performance": {
        "sent": 300,
        "delivered": 250,
        "opened": 220,
        "clicked": 200,
        "unsubscribed": 20,
        "rates": {
          "delivered": 83.33,
          "opened": 73.33,
          "clicked": 66.67,
          "unsubscribed": 6.67,
          "sent": 66.67
        }
      },
      "sms_performance": {
        "sent": 200,
        "delivered": 190,
        "link_clicked": 180,
        "failed": 10,
        "rates": {
          "delivered": 95,
          "link_clicked": 90,
          "failed": 5,
          "sent": 95
        }
      },
      "audience": {
        "current_contacts": 356,
        "previous_contacts": 356,
        "change_percent": 0
      }
    }
  }
}

Errors

StatusMeaning
401The bearer token is missing, expired or invalid
422The request failed validation — the response names the fields
500Unexpected server error

Example request

curl --request GET \
  --url "https://production-api.shoutaboutus.com/api/v1/campaign/dashboard/metrics?start_date=2026-01-01&end_date=2026-01-31" \
  --header 'Authorization: Bearer <bearer-token>' \
  --header 'Accept: application/json'

Did this page help you?