A broadcast is a draft that tells you what is wrong with it
email.broadcast.create makes a draft: a published template, sent from an address on a verified domain, to every contact with current consent for a topic — optionally narrowed by a segment.
It returns readiness immediately. An unverified sender, a missing postal address for the footer, an unknown topic, an unpublished template: each comes back as a problem with a code, what is wrong and the fix. You find out at create time, not when you press send on a campaign to twenty thousand people.
email.broadcast.update changes it while it is still a draft. email.broadcast.list and .get read them back — and get counts progress separately, because the counts on the broadcast itself are written once at send and never recomputed.
Sending is the point of no return, and it is guarded
email.broadcast.send refuses unless all four hold: the sender is on a verified domain, the template is published, the topic exists, and the footer has a postal address. Those are the conditions under which a bulk send is lawful and deliverable, so they are enforced rather than recommended.
It then queues one message per consenting, unsuppressed contact, with that contact’s properties as variables and a personal unsubscribe link. The consent guide covers what counts as consenting; nothing here bypasses it.
Give scheduledAt and the broadcast is queued now and released at that time, rather than depending on something being awake to trigger it.
Pause, resume and cancel do exactly what they say
Pause holds a broadcast that is sending: messages not yet handed to delivery stop. Messages already sent are not recalled — nothing can recall those, and an API that implied otherwise would be lying. Resume puts the held messages back in the queue and continues from where it stopped. Nobody is sent to twice: the ones that already went are untouched, and the audience policy is checked again for each remaining message at the moment it sends — so somebody who unsubscribed during the pause is not sent to. Cancel closes a draft, and cancels any of its messages still queued. Again, what has already gone has gone. SMS mirrors all of it —sms.broadcast.create, .send, .pause, .resume, .cancel — with the same guards and the stricter consent rules the consent guide describes for SMS.
An automation is a broadcast that waits for a reason
email.automation.create takes an event that enrols a contact, an optional filter on that event’s payload, and a tree of steps: wait, send, branch, property.set. A branch can test a contact property, a consent record, or a field of the event that started the run.
It is a draft with readiness, exactly like a broadcast, and nothing runs until you activate it. email.automation.activate is refused with the first readiness problem while any send inside it could not go out — an automation that is half-sendable is worse than one that is off, because it fails silently on a subset of people.
Once active, every matching event enrols its contact and the worker advances the runs.
Changing one that is already running
email.automation.update changes the name, trigger, steps or re-entry rule. Runs already in progress keep the steps they started with only until their next step — so if the tree changes shape, pause it first. A contact halfway through a sequence that is being rewritten underneath them is where the surprising behaviour lives.
Pause stops new enrolments and freezes runs where they are; activating again resumes them. Archive retires it: no new enrolments, every run in progress cancelled, and the definition and history stay readable — because what you sent last quarter is a record you may need long after you stopped sending it.
email.automation.get returns readiness and run counts by status. email.automation.run.list shows the runs, and email.automation.run.cancel stops one contact’s run without touching anybody else’s.
