Version

broadcast.* events

Message broadcast lifecycle: when a send starts, and what it delivered.

Message broadcast lifecycle: when a send starts, and what it delivered. Fires when a creator sends a message to a segment of their members through the project's connector. Two events bracket every send: one as it starts, carrying the audience and how many members it will reach, and one when it finishes, carrying the delivered and failed tallies.

Both fire for broadcasts started anywhere: the dashboard, the bot, the REST API, a Zap or an n8n workflow. They are emitted by the sending job rather than by each entry point, so a broadcast triggered by automation is indistinguishable from one typed into the dashboard.

Background

Audience segments

The audience field on both events is one of:

ValueReaches
allEvery member with a linked chat
customerPaying members
trialingMembers on a trial
leadMembers who started the bot but never subscribed
churnedMembers whose subscription ended
expiring_soonMembers whose access lapses inside expiring_within_days
cancelled_still_activeMembers who turned renewal off but have time left
pausedMembers whose subscription is paused rather than ended
trialing_cardlessMembers on a trial with no card on file
all_pass_holdersHolders of any currently-active pass window
all_pass_holders_not_in_queueAs above, but only those who have not tapped their invite yet
pass_holdersHolders of one named window
pass_holders_not_in_queueHolders of one named window who have not queued

The two single-window pass segments carry a pass_window_id; every other segment reports pass_window_id: null. The four pass segments require the passes capability: a project whose plan no longer includes it cannot address them, and the API refuses the send rather than silently reaching nobody.

expiring_soon reports the horizon it used in expiring_within_days; every other segment reports null. Note that an auto-renewing subscription is never in this segment: a subscription's end date is rewritten on every renewal, so a date alone would describe the next invoice rather than an expiry.

Narrowing by plan

Any segment except lead and the four pass segments can be narrowed to a single plan, and both events then carry that plan in data.plan_id. It composes with the segment rather than replacing it: customer plus a plan means people paying for that plan right now, churned plus a plan means people who held it and left. Segments that cannot be narrowed always report plan_id: null.

This matters for a consumer that counts sends per audience: two broadcast.completed events can now carry the same audience and describe different populations, and plan_id is what tells them apart.

A member is only ever a recipient if they have a chat on that project's bot. Members with no chat, or whose chat belongs to a different bot, are excluded, which is why a recipient count is often well below a project's total membership.

The message body is never in the payload

Neither event carries the text that was sent. Broadcasts are not stored (a broadcast is a send, not a record) and a body is arbitrary creator content up to 4096 characters. Repeating it on every subscribed endpoint would hand it to integrations that only need to know a send happened.

If you need the copy alongside the outcome, send the broadcast through the REST API or a Zap and correlate on project_id and created_at.

What does not emit

A broadcast that is refused never emits either event, because nothing was sent:

  • the project has no connected bot
  • the audience is unknown
  • the body is empty once reduced to the connector's HTML subset
  • a pass segment was requested by a project whose plan no longer includes passes
  • a single-window segment was requested with no window

The REST API and MCP tool reject all of these up front with a validation error. The dashboard and bot paths log and abort.

Required ability

Tokens subscribing to broadcast.* events must carry broadcast:send at mint time. There is no separate read ability: knowing that a broadcast went out, to whom and how many, is the same privilege as being able to send one.

Events

broadcast.queued

WEBHOOK

A broadcast started sending, carrying the audience it resolved to and how many members it will reach.

When this fires

A broadcast began sending. The audience has been resolved to a concrete set of recipients and the first message is on its way.

This fires for broadcasts started anywhere: the dashboard, the bot, the REST API, a Zap or an n8n workflow. The event is emitted by the sending job itself rather than by each entry point, so every route announces a broadcast identically.

This is the start, not the outcome. Delivery runs at roughly 28 messages a second to stay inside the platform's rate limit, so a large broadcast is still sending long after this arrives. Subscribe to broadcast.completed for the tallies.

Caveats

  • recipient_estimate is the count at the moment sending began. Someone who joins mid-send is not included, and someone who blocks the bot mid-send is still counted here but will appear in failed on completion.
  • A member is only a recipient if they have a linked chat on that project's bot. A member with no chat, or one attached to a different bot, is silently excluded, which is why the estimate can be far lower than the project's member count.
  • The message body is not in the payload. Broadcasts are not persisted, and a body can be up to 4096 characters of arbitrary creator content; repeating it on every subscribed endpoint would leak it to integrations that only need to know a send happened.
  • If the audience resolves to zero recipients this still fires, immediately followed by broadcast.completed with sent: 0.

Related events

  • broadcast.completed: the outcome, with sent and failed tallies.
  • Broadcasts: send one programmatically.

Ability to subscribe

A token needs this to subscribe an endpoint to the event.

Header Parameters

SB-Signature*string

t=<unix seconds>,v1=<hex>: the HMAC-SHA256 of "<t>.<raw body>" under the endpoint's secret. Verify it before acting, and refuse a t more than 300 seconds from now. During a secret rotation a v0= signature under the previous secret may precede v1=.

SB-Event-Id*string

The event's ULID, bare. The envelope's id is the same ULID prefixed evt_, so strip the prefix before comparing. Deduplicate on it: a retry carries the same id.

SB-Event-Name*string

The event name, the same as the envelope's type.

Content-Type*string

Always application/json.

User-Agent*string

Always Subscriby-Webhooks/1.0.

Payload

JSONWhat Subscriby posts to your endpoint

The signed JSON envelope posted to your endpoint.

The envelope every event is delivered in.

Responses

2XXAny success status

Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.

defaultAny other status

Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.

broadcast.completed

WEBHOOK

A broadcast finished sending, carrying the delivered and failed tallies.

When this fires

Every recipient in a broadcast has been attempted and the send is over. The payload carries what actually happened.

sent means the platform accepted the message, not that a human read it. There is no read receipt, and a delivered message sitting in a muted chat counts as sent.

Reading the failure count

A steady trickle of failures is normal and not actionable: the overwhelming majority are members who blocked the bot or deleted their account on the platform. Those are permanent; the sender detects them and stops retrying that recipient rather than burning attempts.

What is worth alerting on is a sudden change in the ratio. failed climbing from ~2% to ~40% between two broadcasts usually means the bot's credentials were revoked or the bot was removed from the project's resources, not that forty percent of an audience left at once.

sent + failed can be lower than the recipient_estimate reported by broadcast.queued: a recipient with no chat row is skipped without counting as either.

Caveats

  • Fires once per broadcast, at the end. A broadcast the platform rate-limits heavily can take minutes to finish; there is no progress event in between.
  • If the sending job is released and retried after a long rate-limit, the tallies count the completed run only.
  • A broadcast aborted before sending (no connected bot, an unknown audience, an empty body after sanitisation, or an audience the plan no longer includes) emits neither this nor broadcast.queued. Nothing was sent, so nothing is announced. The REST API refuses those cases up front with a 422 rather than accepting a send that will never leave.

Related events

  • broadcast.queued: the start, with the recipient estimate.

Ability to subscribe

A token needs this to subscribe an endpoint to the event.

Header Parameters

SB-Signature*string

t=<unix seconds>,v1=<hex>: the HMAC-SHA256 of "<t>.<raw body>" under the endpoint's secret. Verify it before acting, and refuse a t more than 300 seconds from now. During a secret rotation a v0= signature under the previous secret may precede v1=.

SB-Event-Id*string

The event's ULID, bare. The envelope's id is the same ULID prefixed evt_, so strip the prefix before comparing. Deduplicate on it: a retry carries the same id.

SB-Event-Name*string

The event name, the same as the envelope's type.

Content-Type*string

Always application/json.

User-Agent*string

Always Subscriby-Webhooks/1.0.

Payload

JSONWhat Subscriby posts to your endpoint

The signed JSON envelope posted to your endpoint.

The envelope every event is delivered in.

Responses

2XXAny success status

Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.

defaultAny other status

Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.

How is this guide?

Version

On this page

Subscriby is a product
designed by you — for you.
No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request