broadcast_message
Send a message through the project's connector to a segment of its members. Destructive and irreversible — preview the audience and get human approval first.
Purpose
Queue a message through the project's connector to a segment of its members. The send runs in the background at the pace the connector declares (28 messages a second on Telegram); the tool returns the audience it resolved and how many members it will reach.
Destructive and irreversible. Every recipient is a real person and the
message lands in their private chat. Call
preview_broadcast_audience first,
show the human the exact message text, the segment and the recipient count,
and get explicit approval before calling this. A broadcast cannot be recalled.
Not idempotent — calling twice sends twice. There is no de-duplication, because two identical broadcasts minutes apart is a legitimate thing a creator may want.
Required ability
broadcast:send
Input schema
{
"type": "object",
"required": ["project_id", "message"],
"properties": {
"project_id": {
"type": "string",
"description": "UUID of the project whose members will receive the message."
},
"message": {
"type": "string",
"description": "The message body, 1-4096 characters. Canonical HTML subset only; anything else is stripped before sending."
},
"audience": {
"type": "string",
"description": "Segment to address. Defaults to `all`."
},
"pass_window_id": {
"type": "string",
"description": "Required for the single-window pass segments; ignored by the others."
},
"plan_id": {
"type": "string",
"description": "Optional. Narrows the segment to one plan. Refused for `lead` and the pass segments."
},
"expiring_within_days": {
"type": "integer",
"description": "How far ahead `expiring_soon` looks, 1-90, default 7. Ignored by every other segment."
}
}
}Output shape
{
"data": {
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"audience": "customer",
"pass_window_id": null,
"plan_id": null,
"expiring_within_days": null,
"recipient_estimate": 128,
"estimated_seconds": 5,
"status": "queued"
}
}status is always queued — this reports what was addressed, not what was delivered. Subscribe to broadcast.completed for the sent and failed tallies.
Narrowing the audience
plan_id composes with audience rather than replacing it: customer plus a plan addresses people paying for that plan right now, churned plus a plan addresses people who held it and left. The plan and the state describe the same subscription, so a member paying for one plan who once trialled another is not matched by the first form.
Four of the segments describe a subscription rather than a member status, which is what a status cannot express — somebody who cancelled but has three weeks left carries the same status as somebody renewing happily:
| Segment | Addresses |
|---|---|
expiring_soon | Access lapses inside expiring_within_days. |
cancelled_still_active | Renewal is off, but time remains. |
paused | Paused rather than ended. |
trialing_cardless | On trial with no card on file. |
An auto-renewing subscription is never `expiring_soon`
A subscription's end date is rewritten to the new period end on every renewal, so a date inside the horizon describes the next invoice, not an expiry — counting it would place every monthly subscriber in this segment once a month. A member appears only once their access genuinely lapses: renewal is off, or the plan does not renew at all.
Refusals
The tool returns a validation error, and sends nothing, when:
- the project has no connected bot
- the body is empty or longer than 4096 characters
- the audience is unrecognised
- a pass segment is requested by a project whose plan no longer includes passes
- a single-window segment is requested with no
pass_window_id - a
plan_idis sent withleador a pass segment, which cannot be narrowed by plan - a
plan_iddoes not belong to the project
A plan filter the segment cannot use is refused rather than ignored: silently dropping it would return a recipient count for a different audience than the one described, and the caller has no way to notice.
Related
preview_broadcast_audience— always call this first.- Broadcasts API — the same operation over REST.
broadcast.*events — react to the outcome.
How is this guide?