Email report (single campaign)
Overview
Get email-channel KPIs (recipients, sent, delivered, opened, clicked, unsubscribed, failed, processed, tests/kiosk counts plus derived rates) and a fixed last-7-day daily timeseries for a single campaign.
Prerequisites
- A bearer token. Callable with Account tokens.
- The
campaignIdof the record you are targeting.
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
GET /api/v1/campaign/{campaignId}/report/email
Authentication
-
Requires a bearer token in the
Authorization: Bearer <bearer-token>header. -
Who can call it: Account tokens.
-
The campaign is scoped to the caller, so a user can only read reports for campaigns owned by their own company (the account/location account).
-
A non-matching id returns 404
Campaign not found.
Rate limit
- No rate limit.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
campaignId | integer | Required | Digits only. |
Query parameters
- Query:
start_date(stringY-m-d, optional) — KPI window start; defaults to the campaign'screated_atstart-of-day. - Query:
end_date(stringY-m-d, optional) — KPI window end; defaults to now end-of-day. Ifstart_date > end_datethe two are swapped. Note: thetimeseries.by_dayblock always covers the last 7 days (now-6 → end) regardless of the date filter.
Response
kpis.recipients_valid(int) — count ofCampaignAudienceDatawithis_email_valid = 'valid', non-test.kpis.sent/delivered/opened/clicked/unsubscribed(int) — counts of non-test rows whose respective*_attimestamp falls in the window.kpis.failed(int) — rows withstatus = 'failed'within the window (failed_at).kpis.processed(int) — non-test rows created in the window.kpis.tests_sent(int) —is_test = truerows created in the window.kpis.kiosk_sent(int) — non-testis_kiosk = truerows created in the window.kpis.rates(object) —processed_rate,delivery_rate,open_rate,click_rate,unsubscribe_rate,sent_vs_audience_rate(floats, percent rounded to 2dp; 0 when denominator is 0).timeseries.by_day(array) — one entry per day for the last 7 days, each{ date (Y-m-d), sent, delivered, opened, clicked, unsubscribed, failed, processed }(ints).
200 Success · 200
200{
"data": {
"status": "success",
"data": {
"kpis": {
"recipients_valid": 1200,
"sent": 1150,
"delivered": 1100,
"opened": 650,
"clicked": 120,
"unsubscribed": 8,
"failed": 50,
"processed": 1200,
"rates": {
"processed_rate": 100,
"delivery_rate": 95.65,
"open_rate": 56.52,
"click_rate": 10.43,
"unsubscribe_rate": 0.7,
"sent_vs_audience_rate": 95.83
},
"tests_sent": 5,
"kiosk_sent": 10
},
"timeseries": {
"by_day": [
{
"date": "2026-06-20",
"sent": 100,
"delivered": 98,
"opened": 60,
"clicked": 12,
"unsubscribed": 1,
"failed": 2,
"processed": 102
}
]
}
}
}
}Errors
| Status | Meaning |
|---|---|
401 | The bearer token is missing, expired or invalid |
404 | No record matches the id you sent |
422 | The request failed validation — the response names the fields |
500 | Unexpected server error |
Example request
curl --request GET \
--url "https://production-api.shoutaboutus.com/api/v1/campaign/123/report/email" \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Accept: application/json'Updated 8 days ago
Did this page help you?
