Skip to content

Message.broadcast

Email a whole Audience, such as your waitlist, in one call.

Action class
send
Approval
Sends on its own
Emits
Message.broadcasted
Sites
Gmail, Outlook
Price
Free
POST https://api.sb/{your-domain}/messages/broadcast

Sends one email to a whole Audience, such as your waitlist, now or at a set time. The hub’s definition of Message.broadcast.

Inputs

NameTypeDefaultMeaning
messageMessageRequiredThe Message to send.
audienceAudienceRequiredWho receives it.
atdatetimenowWhen it goes out; omitted, now. Unset: as soon as its delay window closes.

Outputs

FieldTypeUnitWhat null means
messagesMessage[]None.Never null: one per Contact it reaches. In try mode, the first rendered Message only.
messageMessageNone.Never null.
counts.audienceintegerpeopleNever null: everyone the Audience selects when the call runs.
counts.sendingintegerpeopleNever null: the Audience less both skips.
counts.skippedNoConsentintegerpeopleNever null: Contacts with no Consent for the Message’s purpose.
counts.skippedSuppressedintegerpeopleNever null: Contacts on a Suppression, from any startup of the Company.

Effects

Action class

send: an approval rule on send can make it wait for your OK

Modes
  • try: Counts who it would reach after the Consent and Suppression skips and renders the first Message; nothing sends.
  • send: Returns a pending Action while its delay window runs; then each Message goes out from the broadcast stream.
  • do: Holds the call for the Mode’s hold time, then returns 202 with the pending Action.
Idempotency

Only with a key: the same Idempotency-Key and input return the first Action, and the same key with other input returns 409. Each Contact gets the Message once per broadcast: a retry never sends a second copy to anyone it reached.

Saved or shared

Each sent Message is saved on its Contact, and every reply threads to it.

Emits

Message.broadcasted with { message, audience, counts }

Performed by

Marketing lead

Price

Free on your own account: the platform charges nothing for the call.

Standing approval

It goes out on its own, inside the Limits of your standing approval: a Mandate granted with Mandate.authorize. One approval rule makes it wait for your OK.

On each Venue

SiteFieldsFormats
Gmailfrom, to, subject, body, purposeNone.
Outlookto, subject, body, purposeNone.

Gmail

Through Gmail.

Our fieldGmail’s field
Message.fromraw: From header (Your address, or a send-as alias you set up in Gmail)
Message.toraw: To header
Message.subjectraw: Subject header (A reply keeps the thread’s subject, so Gmail threads it)
Message.bodyraw: text/plain and text/html parts
Message.purposeraw: List-Unsubscribe and List-Unsubscribe-Post headers (A commercial purpose adds the one-click unsubscribe headers Gmail shows as a link)
  • Sends from one inbox. 2,000 messages in a rolling 24 hours on a Google Workspace account, to at most 10,000 recipients; the rest wait for the window with quota-reached.
  • Outside recipients. 3,000 addresses outside your own domain a day, and 500 on one message.
  • Replies. Gmail pushes each new message within seconds; the platform renews the mailbox watch daily, inside the 7 days Gmail allows.

Outlook

Through Outlook.

Our fieldOutlook’s field
Message.tomessage.toRecipients
Message.subjectmessage.subject
Message.bodymessage.body (contentType html or text)
Message.purposemessage.internetMessageHeaders (A commercial purpose adds the one-click unsubscribe headers)
  • Recipients from one mailbox. 10,000 in a rolling 24 hours on Exchange Online; past it the mailbox sends nothing until the oldest sends age out, so the call returns quota-reached with the time.
  • Send rate. 30 messages a minute; the platform paces a broadcast under it, so Microsoft never throttles a send.

What try does

AccountWhat try does
GmailRenders the exact email, headers included, and returns it with the time it would send; nothing reaches Gmail and no draft is saved.
OutlookRenders the exact email or invite and returns it with the time it would go; nothing reaches Outlook and no draft or event is saved.

Refuses when

CheckErrorFixThen call
A broadcast past three times the trailing 7-day Message rate in an hourspam-brakeSend to a smaller List, or wait an hour for the rate to fall.Message.broadcast
A send from a Domain whose DNS records do not resolvedomain-authenticatedAdd the 3 DNS records shown; it passes once they resolve, often within an hour.Domain.authenticate

Every call through an account can also meet the shared account refusals: grant-missing, needs-reauth, account-not-connected, over-mandate, quota-reached, venue-rejected.

The spam-brake payload
JSON
{
  "type": "https://startupbuilder.dev/errors/spam-brake",
  "title": "Sending too fast",
  "status": 422,
  "detail": "A broadcast past three times the trailing 7-day Message rate in an hour.",
  "fix": "Send to a smaller List, or wait an hour for the rate to fall.",
  "next": {
    "verb": "Message.broadcast",
    "input": {}
  },
  "instance": "https://api.sb/leaseline.app/actions/action_1"
}

When it waits

FactValue
send returnsA pending Action, reason: 'awaitingTime', while its delay window runs; Message.broadcasted fires when the last Message is handed off.
Delivered byMessage.broadcasted

Example

Text
Email the launch-day note to my waitlist at 8 a.m. Pacific on November
4.

To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.

Test values

A sk_test_ key answers these the same way every time, at $0 (every test value).

Test valueAlways returnsWhat it is for
audience_test_waitlist{"counts":{"audience":4,"sending":3,"skippedNoConsent":0,"skippedSuppressed":1}}Four test Contacts, one of them on a Suppression, so your agent sees the skip without sending to anyone.
audience_test_spam_rateRefuses with spam-brakeSends as if the Domain’s complaint rate were over the brake, so the broadcast refuses and nothing goes out.
maxCost: 0.0001Refuses with max-costAny priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap.
rate-limited.testRefuses with rate-limitedAny call naming this hostname answers 429 with Retry-After, so your retry logic runs.
sources-busy.testRefuses with sources-busyAny call naming this hostname answers 503 as if every route were busy, and nothing is spent.

Used by