Broadcasts
A broadcast is a single email sent to a segment of your contacts: a product update, a newsletter, an announcement. Where a sequence is an automation that enrolls contacts over time, a broadcast is a one-shot send to whoever matches an audience at send time.
It reuses everything else you’ve built: the same contacts your backend reports, the same lists your forms feed, the same branded templates, and your own sending domain.
Anatomy of a broadcast
| Field | What it is |
|---|---|
name | Internal label (not shown to recipients). |
subject | The email subject line. |
preview | Preview/preheader text shown in the inbox list. |
audience | Who receives it: a saved segment or an inline filter (see below). |
template_id | The branded template to render the body in (optional). |
body_doc | The email body as a TipTap document, with personalization variables. |
from_email | The verified sender address. |
Audience
A broadcast’s audience is either a saved segment or an inline filter:
// Reuse a segment you already built.
{ "kind": "segment", "segmentId": "seg_123" }
// Or define the filter inline.
{ "kind": "inline", "filter": { /* FilterSpec */ } }
The filter is the same FilterSpec used by
segments and sequence triggers, so you target on contact traits, events they did
(or didn’t) fire, list membership, and source. Suppressed and unconfirmed
contacts are excluded automatically, so a broadcast only reaches people who can
actually receive it.
Templates and personalization
Set template_id to render the body inside your branded template (logo, colors,
fonts), shared with sequences and transactional. The body_doc supports
personalization variables that resolve per recipient:
Hi {{ first_name }}, here's what we shipped this month…
Any contact trait can be a variable; missing values fall back gracefully.
Lifecycle
A broadcast moves through these statuses:
draft → scheduled → sending → sent
↘ cancelled
- draft - editable; nothing has been sent.
- scheduled - queued for a future
scheduled_at(skipped when you send now). - sending - the send is in flight.
- sent - finished. (A send that errors out lands in failed.)
- cancelled - you stopped a scheduled or in-flight send.
Preflight
Before sending, run a preflight to validate the broadcast (subject and body present, audience resolves and is non-empty) and see the final recipient count:
// preflight response
{ "matches": 142, "total": 3500, "subject": "Hello" }
matches is who will actually receive it after suppression/confirmation
filtering; total is the project’s contact count for context.
Schedule or send now
Scheduling takes an ISO timestamp; pass null (or omit it on the CLI) to send
immediately:
{ "scheduled_at": "2026-06-01T09:00:00Z" } // null → send immediately
Track it live
Once it’s sending, the live view returns aggregate stats and recent per-recipient activity (delivered, opened, bounced, …), so you can watch a send land in real time.
Sending from the CLI
The CLI drives the whole flow over the Management API. JSON flags
(--audience, --body-doc) accept an inline string or @file.json:
# Create a draft and compose it
letter broadcasts create --name "May newsletter"
letter broadcasts update bc_42 --subject "We shipped something big" \
--audience '{"kind":"segment","segmentId":"seg_123"}' \
--template-id tpl_1 --body-doc @body.json
# Check, then send now or schedule
letter broadcasts preflight bc_42
letter broadcasts schedule bc_42 # send now
letter broadcasts schedule bc_42 --scheduled-at 2026-06-01T09:00:00Z
letter broadcasts live bc_42 --json # watch delivery
letter broadcasts cancel bc_42 # stop a scheduled/sending send
Sending from the Management API
Everything maps onto REST endpoints under your project (see the Management API for auth and conventions):
| Method | Path | What it does |
|---|---|---|
GET | /v1/projects/{slug}/broadcasts | List broadcasts. |
POST | /v1/projects/{slug}/broadcasts | Create a draft. |
GET | /v1/projects/{slug}/broadcasts/{id} | Get one (includes body_doc). |
PATCH | /v1/projects/{slug}/broadcasts/{id} | Edit a draft (subject, audience, body, …). |
DELETE | /v1/projects/{slug}/broadcasts/{id} | Delete a draft. |
POST | /v1/projects/{slug}/broadcasts/{id}/preflight | Validate + count recipients. |
POST | /v1/projects/{slug}/broadcasts/{id}/schedule | Schedule (scheduled_at) or send now (null). |
POST | /v1/projects/{slug}/broadcasts/{id}/cancel | Cancel a scheduled or in-flight send. |
GET | /v1/projects/{slug}/broadcasts/{id}/live | Live status, stats, and recent activity. |
Scheduling a broadcast for immediate send:
curl -X POST https://api.letter.app/v1/projects/acme/broadcasts/bc_42/schedule \
-H "Authorization: Bearer $LETTER_PAT" \
-H "Content-Type: application/json" \
-d '{ "scheduled_at": null }'