Broadcasts API

Send one-to-many campaigns to subscribed contacts using the same queue, suppression list, and delivery events as regular email sends.

How Broadcasts Work

A broadcast starts as a draft. When you send or schedule it, SMTPfast snapshots your selected audience, skips unsubscribed and suppressed addresses, creates one email per recipient, and queues each message for delivery.

Broadcasts are meant for marketing and product updates. They must include an unsubscribe token before they can send.

Audiences can be all subscribed contacts or one manual contact segment. Monthly broadcast limits are tied to your package: Free includes 2, Starter includes 10, Growth includes 50, and Scale includes 200.

Use {{unsubscribe_url}} or {{{RESEND_UNSUBSCRIBE_URL}}} in the markdown, HTML, or text body.

Personalization

Tokens are resolved for each recipient at send time. Add a fallback after a pipe when a value may be blank.

markdown
# Hi {{contact.first_name|there}},

Your workspace is ready.

You are receiving this at {{contact.email}}.

Unsubscribe: {{unsubscribe_url}}

How fast a broadcast goes out

When you send, SMTPfast prepares the recipients in the background and queues one email per contact. The queue sends up to about 14 emails a second, shared by all accounts, so a broadcast to 2,000 contacts usually goes out within a few minutes. The broadcast page shows the progress.

A new account sends in stages for its first week, which protects your domain's reputation and ours. A send larger than the stage allows is refused with a 429 that names the stage; scheduled sends count in the hour they go out.

Account ageRecipients per sendPer hourPer day
First hour100100200
First day5002501,000
First week2,0001,0003,000

To spread a large audience instead of sending it all at once, set send_over_minutes on the broadcast or on the send (in the dashboard: Delivery, on the review step). Recipients then go out evenly over that window from the send time, or from scheduled_at: recipient i of N goes out at start + i × window / N. Use 0 to send all at once, or 15 to 4320 minutes (72 hours). The window must end within 30 days.

If sending falls more than a minute behind that plan (for example during an outage on our side), the recipients still waiting are spread again evenly over the time left in the window, so they do not all go out at once when sending resumes. If the window is already over, the rest goes out at the normal broadcast send rate. The scheduled_at of each waiting email moves with it.

A spread send is counted in the hours it lands in, so it can fit the hourly limit above: in the first week, 2,000 recipients over 4 hours is 500 an hour and is accepted, while the same send all at once is refused. The daily limit still counts the whole send. Each hour of the window must also fit what else you have scheduled in it.

While it runs, the broadcast page shows how many have gone out. Canceling the broadcast stops every recipient that has not gone out yet and refunds them.

Broadcast Object

json
{
  "object": "broadcast",
  "id": "clx_broadcast123",
  "name": "May product update",
  "audience": "segment",
  "audience_meta": { "segment_id": "seg_product" },
  "from": "[email protected]",
  "reply_to": null,
  "subject": "New features for {{contact.first_name|there}}",
  "status": "draft",
  "scheduled_at": null,
  "send_over_minutes": 0,
  "queued_at": null,
  "sent_at": null,
  "recipient_count": 0,
  "metrics": {
    "total": 0,
    "delivered": 0,
    "opened": 0,
    "clicked": 0,
    "delivery_rate": 0,
    "open_rate": 0,
    "click_rate": 0
  },
  "created_at": "2026-05-05T12:00:00.000Z",
  "updated_at": "2026-05-05T12:00:00.000Z"
}
GET/v1/broadcasts

List broadcasts in newest-updated order. Use status and q query parameters to filter the list.

Parameters

ParameterTypeRequiredDescription
statusstringNoall, draft, scheduled, queued, sent, or canceled
qstringNoSearch by name, subject, or from address
limitnumberNoNumber of broadcasts to return, up to 100
pagenumberNoPage number for pagination

Response

json
{
  "object": "list",
  "data": [
    {
      "id": "clx_broadcast123",
      "name": "May product update",
      "status": "draft",
      "metrics": { "total": 0, "delivered": 0 },
      "created_at": "2026-05-10T09:00:00.000Z",
      "updated_at": "2026-05-10T09:00:00.000Z"
    }
  ],
  "has_more": false,
  "page": 1,
  "page_size": 50,
  "filtered_total": 1,
  "total": 1,
  "status_counts": { "draft": 1 }
}
POST/v1/broadcasts

Create a draft broadcast. You can save partial drafts, target all contacts or a manual segment, then update the campaign before sending. Pass template_id to start from a template: its content fills the draft and any field you send wins.

Request Body

json
{
  "name": "May product update",
  "audience": "segment",
  "segment_id": "seg_product",
  "from": "[email protected]",
  "subject": "New features for {{contact.first_name|there}}",
  "markdown": "# Hi {{contact.first_name|there}},\n\nHere is what changed.\n\nUnsubscribe: {{unsubscribe_url}}"
}

Response

json
{
  "object": "broadcast",
  "id": "clx_broadcast123",
  "name": "May product update",
  "status": "draft",
  "created_at": "2026-05-10T09:00:00.000Z",
  "updated_at": "2026-05-10T09:00:00.000Z"
}
GET/v1/broadcasts/:id

Retrieve a broadcast with rollup metrics, recent recipients, recipient events, and link click counts.

PATCH/v1/broadcasts/:id

Update a draft or scheduled broadcast. Updating a scheduled broadcast cancels the old schedule and returns it to draft.

Request Body

json
{
  "subject": "Updated subject",
  "preview_text": "A short inbox preview"
}
POST/v1/broadcasts/:id/test

Queue a test email to one address using sample personalization data.

Request Body

json
{
  "to": "[email protected]"
}

Response

json
{
  "object": "email",
  "id": "email_abc123",
  "status": "queued"
}
POST/v1/broadcasts/:id/send

Send immediately or schedule within 30 days. The send creates a recipient snapshot from the selected audience and queues one email per eligible contact. Pass send_over_minutes to spread the recipients evenly over that window; left out, the broadcast's saved setting applies.

Only verified sending domains can send broadcasts. Monthly email quota and monthly broadcast quota are checked before recipients are queued.

Request Body

json
{
  "scheduled_at": "2026-05-12T14:00:00.000Z",
  "send_over_minutes": 240
}

Response

json
{
  "object": "broadcast",
  "id": "clx_broadcast123",
  "name": "May product update",
  "status": "scheduled",
  "scheduled_at": "2026-05-12T14:00:00.000Z",
  "created_at": "2026-05-10T09:00:00.000Z",
  "updated_at": "2026-05-11T16:20:00.000Z",
  "recipients": 1240,
  "skipped": 18,
  "batch_id": "batch_abc123"
}
POST/v1/broadcasts/:id/cancel

Cancel a scheduled broadcast, or stop one that is sending or spread over a window. Emails that have not gone out yet are dropped and refunded; delayed queue jobs are removed where possible.

DELETE/v1/broadcasts/:id

Delete a draft broadcast. Sent, queued, scheduled, and canceled broadcasts are retained for audit history.

POST/v1/broadcasts/:id/duplicate

Copy a broadcast into a new draft. Content, sender and targeting carry over; the schedule, recipients and send history do not. Pass name for the copy, or get the original's with (copy) appended.

Parameters

ParameterTypeRequiredDescription
namestringNoName for the copy
GET/v1/broadcasts/:id/clicked-links

Every link clicked in this broadcast, ordered by total clicks. clicks counts every click; unique_clicks counts distinct recipients, so one person clicking four times is four and one.

Response

json
{
  "broadcast_id": "bc_01j9x3n8r1",
  "links": [
    { "url": "https://acme.com/pricing", "clicks": 42, "unique_clicks": 31 }
  ],
  "total_clicks": 42
}

Recipients and audience preview

List who received a broadcast and what happened, and check an audience before you send.

GET/v1/broadcasts/{id}/recipients

Recipients for one event type, newest first. Same as Resend's List Recipients.

Parameters

ParameterTypeRequiredDescription
typestringNosent, delivered, opened, clicked, bounced, complained, unsubscribed or suppressed
bounce_typestringNopermanent, transient or undetermined, with type=bounced
emailstringNoRecipients whose address contains this text
limitintegerNo1 to 100, default 20
afterstringNoCursor: the last recipient id of the previous page
GET/v1/broadcasts/audience

How many contacts a broadcast to everyone, or to one segment, would reach after unsubscribes, suppressions and invalid addresses are skipped.

Parameters

ParameterTypeRequiredDescription
segment_idstringNoPreview one segment