Skip to main content

Overview

A broadcast is one email (or, for a webinar session, one text) sent once to an audience: everyone with an email address, a saved segment, or a webinar session’s registrants. Broadcasts are scheduled through the API, never sent immediately, and committing one takes two calls:
  1. Plan — POST /v1/broadcasts/{broadcast_id}/plan with a send_at shows exactly what would happen: how many people it reaches, when it goes out, who it is from, the body as one real recipient receives it, and every check that would stop or surprise the send. When nothing blocks, it returns a plan_token.
  2. Schedule — POST /v1/broadcasts/{broadcast_id}/schedule with that plan_token commits the plan. If anything the plan covered has changed since (content, variables, sender, audience, a segment’s filters, timing), the plan is over an hour old, or the send time is now less than an hour away, it is refused and you plan again.
A broadcast always goes out at least an hour after it is scheduled, and until then it can be pulled back — with POST /v1/broadcasts/{broadcast_id}/unschedule, or Unschedule on the broadcast in the dashboard. Everything before /schedule is safe to call freely; drafts and plans reach no one.
The same operations are MCP tools on https://api.flywheel.cx/mcp: create_broadcast, update_broadcast, list_broadcast_variables, plan_broadcast, schedule_broadcast, unschedule_broadcast, get_broadcast_stats and list_senders.

Authentication

API keys are managed in the dashboard under Settings → API Keys. Every broadcast, segment, sender and webinar is resolved inside the organization the key belongs to.

Variables

Broadcasts use Flywheel’s variable system — the same one the dashboard editor saves and workflow messages use. The body holds {{var_<id>}} placeholders, and variables says what fills each one:
GET /v1/broadcasts/variables lists what variables can read: the recipient’s fields, your organization’s custom properties (by key), and — on a broadcast tied to a webinar — the session: webinar_title, webinar_start_time, join_url (the recipient’s personal link) and add-to-calendar links. Where placeholders can go, matching what the dashboard editor keeps when someone edits the broadcast there:
  • Email text: {{var_<id>}}.
  • A link: the whole href is a {{link_var_<id>}} whose variable is exactly one path — <a href="{{link_var_join}}">Join</a>. A linked image is an <a href> around the <img>.
  • Texts: {{var_<id>}} anywhere; texts are plain, so put a URL variable in the text.
Placeholders without a definition, variables whose path does not resolve, template syntax that is not a variable, and variables in the subject or preview text (which are sent as written) are refused rather than sent blank. So are scripts, forms, inline event handlers and javascript: links. Variables the body does not use are dropped.

Create a Broadcast

POST /v1/broadcasts
Keep the email HTML to what the dashboard editor can reopen — p, h1–h3, strong, em, a, ul/ol/li, img, hr, br — since your organization’s email layout (logo, footer, unsubscribe link) wraps it at send. A broadcast created here appears in the dashboard’s Broadcasts list and opens in its editor like any other.

Plan

POST /v1/broadcasts/{broadcast_id}/plan
  • send_at must be at least an hour from now (and at most a year). A webinar broadcast timed from its session (webinar_offset_minutes) plans for that time instead and takes no send_at.
  • recipients is counted the way the sender counts, now; the audience is resolved again when it sends, and people who opted out, bounced or complained are skipped then.
  • delivery.paced_over_hours: sends to a list are spread over three hours from send_at; webinar broadcasts go out at once.
  • checks with level: "error" block scheduling (no plan_token is issued) — for example send_at_required, send_at_too_soon, subject_missing, sender_missing, sender_domain_unverified, variable_missing, webinar_canceled, allowance_used_up. warning checks don’t block but are worth reading: everyone (the broadcast goes to your whole list), no_recipients_yet, allowance_short, variable_unresolvable, gmail_clipping, sent_before.
Planning writes nothing.

Schedule

POST /v1/broadcasts/{broadcast_id}/schedule
It returns 409 if the broadcast changed since it was planned or the plan expired — plan again — and 400 if something now blocks it, including a send time that is less than an hour away.

Unschedule

POST /v1/broadcasts/{broadcast_id}/unschedule Takes a scheduled broadcast back to draft, up to the moment it starts sending. Refused once sending has begun.

Read, Edit and Delete

Any change to a broadcast invalidates an earlier plan. Plan again after editing, and review it before scheduling.