campaign.finished
POST
your webhook addressCampaign finished. A campaign of the console completed or was stopped. The numbers are those of the moment it finished: the delivery of its messages goes on and comes as message.* events.
Body
| Field | Type | Description |
|---|---|---|
type | string | Always campaign.finished. |
timestamp | string (date-time) | When the event happened, UTC. |
data | object | |
data.id | string | The campaign, cmp_…. |
data.name | string | |
data.status | string | One of: completed, stopped. |
data.recipients | integer | Recipients of the campaign, the control group included. |
data.sent | integer | Messages accepted for sending. |
data.skipped | integer | Recipients that got no message: a stop list, an invalid number, a missing variable. |
data.control | integer | The control group: recipients left without a message on purpose. |
data.started_at | string (date-time), nullable | |
data.finished_at | string (date-time) |
json
{
"type": "campaign.finished",
"timestamp": "2026-11-02T14:30:00+00:00",
"data": {
"id": "cmp_CgdWeHQNKTXRFhMrxkn9z",
"name": "Reactivation — November",
"status": "completed",
"recipients": 12840,
"sent": 12115,
"skipped": 83,
"control": 642,
"started_at": "2026-11-02T12:00:00+00:00",
"finished_at": "2026-11-02T14:30:00+00:00"
}
}Headers
| Header | Description |
|---|---|
webhook-id | The delivery, whd_…. The same on every attempt of one delivery: use it to drop a repeated delivery. |
webhook-timestamp | Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes. |
webhook-signature | v1, and the base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body}, keyed with the secret (the part after whsec_, base64-decoded). |
content-type | application/json |
user-agent | ACE-SEND-Webhooks/1 |
Check the signature before you trust the body, answer 2xx within 5 seconds and do the work afterwards. See Webhooks for the signature check, retries and duplicates.