Skip to content

Broadcast events ​

Events emitted as a broadcast recipient's delivery status changes across any channel (email, sms, whatsapp, push, voice).

See Outgoing webhooks for how delivery, retries and the common event / event_id fields work.

Delivery lifecycle ​

A single recipient typically produces two events:

  1. broadcast.sent, fired the moment Bunce attempts the delivery.
  2. A terminal event (broadcast.delivered, broadcast.failed, broadcast.not_contacted, or an engagement event like broadcast.opened / broadcast.clicked) reflecting the real outcome.

The broadcast.sent event records the attempt, the terminal event records the result.

Common fields ​

All payloads below are shown in full. These fields appear on every broadcast event:

FieldTypeNotes
eventstringEvent name, one of the values below.
event_idstringUnique id for this event.
broadcast_idstringId of the broadcast this event belongs to.
subjectstringBroadcast subject / title.
timestampstring (ISO 8601)When the status occurred (action_at).
channelstringDelivery channel: email, sms, whatsapp, push, or voice.
page_countintNumber of pages in the broadcast.
sender.namestringConfigured sender name.
sender.emailstring | nullSender email; null on non-email channels.
recipient.idstringInternal company-customer id.
recipient.first_namestringRecipient first name.
recipient.last_namestringRecipient last name.
recipient.emailstring | nullRecipient email.
recipient.phonestring | nullRecipient phone number.
recipient.company_customer_idstringExternal / business customer id.

Depending on the channel, either email or phone will be the relevant contact field; the other may be null.

Events ​

broadcast.sent ​

The delivery was attempted / handed to the provider.

json
{
  "event": "broadcast.sent",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7a8",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:30:00.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  }
}

broadcast.delivered ​

The provider confirmed the message reached the recipient.

json
{
  "event": "broadcast.delivered",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7b9",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:30:05.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  }
}

broadcast.opened ​

The recipient opened the message (open tracking).

json
{
  "event": "broadcast.opened",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7c0",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:41:12.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  }
}

broadcast.clicked ​

The recipient clicked a tracked link. Adds url.

FieldTypeNotes
urlstringThe link the recipient clicked.
json
{
  "event": "broadcast.clicked",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7d1",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:43:20.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  },
  "url": "https://acme.test/offer"
}

broadcast.failed ​

The delivery failed. Adds failure_reason.

FieldTypeNotes
failure_reasonstring | nullProvider or system message describing the failure.
json
{
  "event": "broadcast.failed",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7e2",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:30:08.000000Z",
  "channel": "sms",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": null
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": null,
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  },
  "failure_reason": "Invalid phone number"
}

broadcast.not_contacted ​

The recipient was skipped and never contacted (e.g. unsubscribed, invalid contact details). Adds not_contacted_reason.

FieldTypeNotes
not_contacted_reasonstring | nullWhy the recipient was skipped.
json
{
  "event": "broadcast.not_contacted",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7f3",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T09:30:00.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  },
  "not_contacted_reason": "Recipient unsubscribed"
}

broadcast.complained ​

The recipient marked the message as spam / complained (email feedback loops). Adds reason.

FieldTypeNotes
reasonstring | nullComplaint detail from the provider.
json
{
  "event": "broadcast.complained",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7g4",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T10:02:00.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  },
  "reason": "Reported as spam"
}

broadcast.unsubscribed ​

The recipient unsubscribed. Adds reason.

FieldTypeNotes
reasonstring | nullUnsubscribe detail.
json
{
  "event": "broadcast.unsubscribed",
  "event_id": "01j8z6f3q2m9r7t1v4x5y6z7h5",
  "broadcast_id": "01j8y9k2m3n4p5q6r7s8t9u0v1",
  "subject": "October promo",
  "timestamp": "2026-10-13T10:10:00.000000Z",
  "channel": "email",
  "page_count": 1,
  "sender": {
    "name": "Acme Store",
    "email": "news@acme.test"
  },
  "recipient": {
    "id": "01j8x1y2z3a4b5c6d7e8f9g0h1",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "phone": "+2348012345678",
    "company_customer_id": "cust_12345"
  },
  "reason": "Unsubscribed via link"
}

Event-to-channel availability ​

Eventemailsmswhatsapppushvoice
broadcast.sentyesyesyesyesyes
broadcast.deliveredyesyesyesyesyes
broadcast.openedyesyesyesnono
broadcast.clickedyesyesyesnono
broadcast.failedyesyesyesyesyes
broadcast.not_contactedyesyesyesyesyes
broadcast.complainedyesnononono
broadcast.unsubscribedyesyesyesyesno

Not every event fires for every recipient. Engagement events (broadcast.opened, broadcast.clicked, broadcast.complained, broadcast.unsubscribed) depend on tracking being available for that message and on recipient behavior.