Docs Go to app →

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

FieldWhat it is
nameInternal label (not shown to recipients).
subjectThe email subject line.
previewPreview/preheader text shown in the inbox list.
audienceWho receives it: a saved segment or an inline filter (see below).
template_idThe branded template to render the body in (optional).
body_docThe email body as a TipTap document, with personalization variables.
from_emailThe 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):

MethodPathWhat it does
GET/v1/projects/{slug}/broadcastsList broadcasts.
POST/v1/projects/{slug}/broadcastsCreate 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}/preflightValidate + count recipients.
POST/v1/projects/{slug}/broadcasts/{id}/scheduleSchedule (scheduled_at) or send now (null).
POST/v1/projects/{slug}/broadcasts/{id}/cancelCancel a scheduled or in-flight send.
GET/v1/projects/{slug}/broadcasts/{id}/liveLive 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 }'