Splashify RCS

Docs

Open panel
Panel

Broadcasts

A broadcast pairs one approved template with one contact list. The API kicks off the send when its status is running (immediate) or scheduled + the scheduled time has passed.

Team-member access: operators can call every endpoint on this page as long as the target bot_id is in their assigned bot set; viewers get 403 not_operator on any mutation and see only their assigned bots on the list/get paths. See the Team members reference for the role matrix.

http
POST   /api/v1/rcs/broadcasts
GET    /api/v1/rcs/broadcasts
GET    /api/v1/rcs/broadcasts/{id}
POST   /api/v1/rcs/broadcasts/{id}/start
POST   /api/v1/rcs/broadcasts/{id}/send-now
POST   /api/v1/rcs/broadcasts/{id}/cancel
GET    /api/v1/rcs/broadcasts/{id}/targets
GET    /api/v1/rcs/broadcasts/{id}/failure-reasons
POST   /api/v1/rcs/broadcasts/{id}/remove-not-on-rcs
GET    /api/v1/rcs/broadcasts/{id}/button-taps
POST   /api/v1/rcs/broadcasts/{id}/retarget

The bot must be registered for promotional traffic

Every endpoint on this page that puts messages on the carrier, create, start, send now, retarget, and both write endpoints on recurring broadcasts, first checks what the bot is registered for with the carrier.

json
{
  "success":      false,
  "code":         "bot_not_promotional",
  "message":      "\"Acme Orders\" is registered with the carrier as a Transactional bot, so it cannot run broadcasts. …",
  "bot_use_case": "transactional",
  "use_instead":  "POST /api/v1/rcs/messages/send"
}

Branch on code, not on the message text. use_instead names the endpoint to call for this bot's traffic, a Transactional or OTP bot keeps full use of send message, test sends and auto-replies; only bulk fan-out is refused.

GET /rcs/bots returns a can_broadcast boolean per bot so you can filter before you build a request. Read that flag rather than deriving the rule from use_case yourself, the flag is where the rule actually lives.

The check runs again at start and send now, not only at create: a draft can outlive a correction to the bot's registration, and start is what actually sends. It is evaluated before any wallet reservation, so a refusal never leaves funds held.

Status lifecycle

text
draft  →  scheduled  →  running  →  completed
                              ↘    ↘
                              cancelled
                              failed
  • draft, created but not yet sendable. Call /start to flip it.
  • scheduled, scheduled_at is in the future; the send starts automatically when the time arrives.
  • running, actively sending.
  • completed, every target has settled (sent, delivered, read, or failed). Fires the "Broadcast finished" email.
  • cancelled. You called /cancel. Messages already sent stay charged, except any that fail after that, which are refunded; the hold for the rest is returned.
  • failed, the send couldn't proceed (missing credentials, empty wallet, missing template). A scheduled broadcast that fell due after today's spend limit was reached also ends here, with status_reason: "spend_limit_reached", see Daily spend limit reached.

Create

http
POST /api/v1/rcs/broadcasts
{
  "name":         "May launch announcement",
  "bot_id":       "e8bb61e0-8500-11ef-9c9a-4bc60d7a1e2f",
  "template_id":  "1f7a…",
  "list_id":      "a1b2…",
  "audience":     "rcs",
  "scheduled_at": "2026-05-28T08:00:00Z"
}

audience is optional and says who on the list the broadcast sends to:

Opted-out numbers are never sent in any choice. Spaces around the value and its case do not matter. Any other value is refused with HTTP 400:

json
{
  "success": false,
  "code":    "invalid_audience",
  "message": "audience must be rcs, not_rcs or all"
}

A check is optional. On a list that was never checked, rcs and all both send to every number that has not opted out (rcs still skips the 30-day not-on-RCS numbers), and not_rcs is refused as none_cannot_get. See Reachability filter.

bot_id selects the sender bot for this broadcast. It must be an active bot owned by the calling account. When omitted, the request falls back to the caller's default bot for one release cycle. See the Bots reference for how to list your bots and pick a bot_id.

Only an active bot may broadcast. Anything else, including a processing bot whose carrier approval is still open, returns HTTP 403.

The check runs on every path that can start a fan-out, not just this one: /start, /send-now, /retarget and the recurring endpoints all re-read the bot at the moment they run. A broadcast drafted while a bot was active cannot be started later on one that no longer is.

json
{
  "success": false,
  "code":    "bot_not_active",
  "message": "This bot is not active. Wait for admin activation or pick another bot."
}

scheduled_at is optional. Omit it (or send a past timestamp) and the broadcast runs as soon as you call /start.

The template must be in effective_status = approved, otherwise the endpoint returns 403.

Account-suspended block

If your account status is suspend, this endpoint returns HTTP 403 with:

json
{
  "success": false,
  "code":    "account_suspended",
  "message": "Account suspended. <reason>. Reply to your suspension email to discuss."
}

The rest of the panel (templates, contact lists, invoices, past broadcasts) stays fully accessible while suspended. Only new sends are blocked. When the suspension is lifted, an "Account reactivated" email fires and this endpoint accepts again.

Response:

json
{
  "success":       true,
  "broadcast_id":  "b1b2…",
  "total_count":   18324,
  "audience":      "rcs",
  "status":        "draft",
  "template_name": "order_shipped",
  "list_name":     "May launch, opted in"
}

total_count here is how many numbers the audience sends to, counted at Create. When the recipients are prepared it becomes the number written for sending.

Nobody to send to

Before it saves anything, Create counts who the broadcast would reach from this bot for its audience, with the same rule the send uses (see Reachability filter). When that reaches nobody, Create answers HTTP 400. Nothing is saved and no money is held:

json
{
  "success": false,
  "error":   "no_reachable_recipients",
  "code":    "no_reachable_recipients",
  "reason":  "all_unreachable",
  "message": "None of the numbers on this list can get RCS messages. Pick another list."
}

Branch on code, and on reason for your own wording. To know before you call Create, ask the audience endpoint: choices has the count for each audience, and its reason is the one Create would give for rcs.

all_unreachable can come from a check made with any of your bots, and only a bot that supports number checks can make one. It applies to a broadcast from any of your bots, including one that cannot check numbers. It is also the reason when every number left failed as not on RCS with this bot in the last 30 days (see Reachability filter). A list never checked is sent to every number that has not opted out. If the count cannot be made, Create is not refused; the send still applies the same rule for its audience when the recipients are prepared.

Daily spend limit reached

When the account owner has set a daily spend limit and today's spend has reached it, Create, Start and Send now answer HTTP 409 before the broadcast itself is checked. Nothing is saved, started or held:

json
{
  "success":     false,
  "error":       "spend_limit_reached",
  "code":        "spend_limit_reached",
  "message":     "Today's spend limit of ₹5,000 is reached. New broadcasts can start again after midnight, or the account owner can raise the limit in Settings.",
  "daily_limit": 5000,
  "today_spend": 5012.4,
  "resets_at":   "2026-09-27T18:30:00Z"
}

Which calls it refuses:

A broadcast that is already running is never stopped, so a day's spend can pass the limit. A scheduled broadcast that has never sent and falls due while the limit is reached does not start: it ends failed with status_reason: "spend_limit_reached", nothing is sent, and a prepaid hold is released. Send it again with a new Create.

The limit guards your budget, so a read that fails lets the call through rather than refusing a send.

Personalisation: variables and fallbacks

If the template contains {{1}}, {{2}}, … variables, attach a param_map to the Create request so each recipient gets their own values:

http
POST /api/v1/rcs/broadcasts
{
  "name":        "May launch announcement",
  "bot_id":      "e8bb61e0-…",
  "template_id": "1f7a…",
  "list_id":     "a1b2…",
  "param_map": [
    { "index": 1, "column": "name",     "fallback": "there"    },
    { "index": 2, "column": "order_id", "fallback": ""         },
    { "index": 3, "column": "",         "fallback": "DIWALI20" }
  ]
}

Each entry fills one template variable:

Every variable needs an entry with a column or a fallback. If one is missing, Create is refused:

json
{
  "success": false,
  "code":    "param_map_required",
  "field":   "param_map",
  "message": "Fill every template variable: {{2}} has no column or fallback."
}

Per recipient, each variable takes the column's value, or the fallback when the column is empty. A recipient that still has no value (empty column, empty fallback) is skipped: the target is marked failed with a failure_reason such as No value for {{2}} in the message text, and it is not charged. The same happens when a value pushes a field over its limit (for example a card title over 200 characters).

Variables are filled in the message text, card titles and descriptions, suggestion labels, and at the end of a suggestion URL, where the value is URL-encoded.

Header image override

On bots that support it, you can swap the header image for this one broadcast without recreating the template. On other bots the field is ignored:

json
{
  "name":               "May launch announcement, variant B",
  "template_id":        "1f7a…",
  "list_id":            "a1b2…",
  "image_override_url": "https://cdn.example.com/promo-may.png"
}

The override replaces the template's first mediaUrl for every message on this broadcast.

Preview

http
POST /api/v1/rcs/broadcasts/preview
{
  "template_id":        "1f7a…",
  "list_id":            "a1b2…",
  "param_map":          [ … same shape as Create … ],
  "image_override_url": "https://cdn.example.com/promo.png"
}

Returns up to three sample renders, one per real recipient, so a UI or an automated test can show exactly what a recipient will receive before the broadcast is saved:

json
{
  "success":  true,
  "provider": "jiocx",
  "previews": [
    {
      "phone":      "+919876543210",
      "components": { "type": "text", "text": "Hi Asha, your order 1234 has shipped. Use DIWALI20 on your next order." }
    },
    {
      "phone":      "+919876543211",
      "components": { "type": "text", "text": "Hi there, your order {{2}} has shipped. Use DIWALI20 on your next order." }
    }
  ]
}

A preview that still shows a {{n}} is a recipient with no value for that variable. At send time that recipient is skipped and not charged.

Lists with zero members return one all-fallback preview so the caller can still see the layout.

Start

http
POST /api/v1/rcs/broadcasts/{id}/start

Returns { "success": true, "status": "running" } (or scheduled if scheduled_at is still in the future).

While the broadcast is draft or preparing, Start counts its audience again, since the list may have changed after Create. A send that reaches nobody is refused with the same 400 no_reachable_recipients as Create, before any wallet hold.

A prepaid broadcast holds money for the sends when it starts. A broadcast still preparing holds the count of its audience, made fresh at Start. While a check on the list is running, it holds the count of every number that has not opted out instead, since the check can still move numbers into the choice. A check that stopped part way changes nothing more, so it holds the count of its audience. A broadcast whose recipients are already prepared holds its total_count. What is not used returns when the broadcast ends. A check never blocks Start: the send uses the answers saved when its recipients are prepared.

Once today's spend limit is reached, Start is refused with 409 spend_limit_reached, unless the broadcast is scheduled for a later day.

Send now (override a scheduled broadcast)

http
POST /api/v1/rcs/broadcasts/{id}/send-now

Flips a scheduled broadcast to running immediately, ignoring its scheduled_at. The send starts within seconds.

Rules:

  • Only valid on broadcasts currently in scheduled status. Any other state returns HTTP 409.
  • Blocked for suspended accounts with account_suspended (same shape as Create).
  • Refused with 409 spend_limit_reached once today's spend limit is reached.
  • No email fires on send-now itself. You'll get the usual "Broadcast finished" summary when it completes.

Response:

json
{ "success": true, "status": "running", "message": "Broadcast queued to send immediately." }

Cancel

http
POST /api/v1/rcs/broadcasts/{id}/cancel

Refuses with 409 if the broadcast is already in a terminal state.

List + get

http
GET /api/v1/rcs/broadcasts?size=50
GET /api/v1/rcs/broadcasts/{id}

The list is newest first, by when each broadcast was created. It returns size rows (default 50, max 200) in broadcasts, and while there are more, next_cursor and has_more: true. Pass next_cursor back as cursor for the next page; the order holds across pages. The newest 50,000 broadcasts can be paged through. A read that fails answers 503 broadcasts_unavailable; try again.

Get answers { "success": true, "broadcast": { … } }. Each row carries the live counters:

json
{
  "broadcast_id":    "b1b2…",
  "name":            "May launch announcement",
  "status":          "running",
  "total_count":     18324,
  "sent_count":      8124,
  "delivered_count": 7812,
  "read_count":      4103,
  "clicked_count":   612,
  "failed_count":    12,
  "optout_skipped_count":      77,
  "unreachable_skipped_count": 240,
  "ctr":             7.83,
  "started_at":      "2026-05-28T08:00:01Z",
  "created_at":      "2026-05-28T07:58:40Z"
}

Get also returns not_on_rcs_skipped_count, status_reason and audience (rcs, not_rcs or all; broadcasts created before the field read rcs):

json
{
  "broadcast_id":             "b1b2…",
  "not_on_rcs_skipped_count": 36,
  "status_reason":            "",
  "audience":                 "rcs"
}

status_reason says why a rule ended the broadcast on its own. It is "" for almost every broadcast, and "spend_limit_reached" for a scheduled one that fell due after today's spend limit was reached.

Counters update in real time from delivery webhooks.

When the broadcast was created with a param_map and/or a header image override, both come back on Get too:

json
{
  "broadcast_id":       "b1b2…",
  "param_map": [
    { "index": 1, "column": "name",     "fallback": "there"    },
    { "index": 2, "column": "order_id", "fallback": ""         },
    { "index": 3, "column": "",         "fallback": "DIWALI20" }
  ],
  "image_override_url": "https://cdn.example.com/promo.png"
}

Broadcasts without these fields simply omit them.

Counter guide

Numbers left out because they are not in the audience (for example the reachable numbers of a not_rcs broadcast) have no counter.

CTR, click-through rate

Each row carries ctr: clicked_count divided by delivered_count, times 100, and 0 when nothing was delivered. The same figure client-side:

text
const ctr = row.delivered_count > 0
  ? (row.clicked_count / row.delivered_count) * 100
  : 0;

Notes:

  • CTR is computed against delivered (not sent), failed sends never suppress the rate.
  • clicked_count counts each person once per broadcast, however many times they tap, so repeated taps don't inflate the rate. Every tap is counted per button on Button taps.
  • If you post templates via the API with your own postback values, keep each one short plain text (up to 90 characters). No marker is needed: the value is sent exactly as you save it.
  • Delivery rate can be computed the same way: (delivered_count / sent_count) * 100.
  • Read rate: (read_count / delivered_count) * 100.

Targets

http
GET /api/v1/rcs/broadcasts/{id}/targets?size=200

Returns up to size recipient rows (default 200, max 1000):

json
{
  "success": true,
  "targets": [
    {
      "recipient_phone": "+919876543210",
      "state":           "sent",
      "sent_at":         "2026-05-28T08:00:02Z",
      "delivered_at":    "2026-05-28T08:00:03Z",
      "read_at":         "2026-05-28T08:07:41Z",
      "failure_reason":  ""
    },
    {
      "recipient_phone": "+919876543299",
      "state":           "failed",
      "failure_reason":  "Recipient has opted out of RCS, Remove them from the list, don't retry."
    }
  ]
}

state values: queued, sent, delivered, read, failed, expired. Each row also carries clicked_at once the person tapped a button.

Page on with next_cursor: pass it back as cursor. has_more is true while there are more rows.

Search the whole broadcast

http
GET /api/v1/rcs/broadcasts/{id}/targets?state=failed&size=200
GET /api/v1/rcs/broadcasts/{id}/targets?phone=98765
GET /api/v1/rcs/broadcasts/{id}/targets?phone=%2B919876543210
  • state returns only rows in that state. state=clicked returns the rows with a clicked_at, whatever their state.
  • phone with digits returns numbers that contain them. A full number starting with + (sent as %2B) returns that one row.
  • Numbers left out before sending have no row, so they never match.

A search reads up to 50,000 rows per call and returns the matches with a next_cursor, so a call can come back with few or no rows and has_more: true. Keep calling with cursor until you have enough rows or has_more is false. scanned says how many rows that call read.

failure_reason on failed rows is a customer-actionable message with a resolution hint. See the Errors reference for the full mapping table.

Failure reasons

http
GET /api/v1/rcs/broadcasts/{id}/failure-reasons

The broadcast's failed messages counted by reason, largest first. Counts only, no phone numbers: every role can call it, and so can an API key with broadcasts:read.

json
{
  "success": true,
  "failed": 640,
  "source": "live",
  "complete": true,
  "reasons": [
    { "reason": "not_on_rcs", "count": 621 },
    { "reason": "blocked",    "count": 12 },
    { "reason": "other",      "count": 7 }
  ],
  "not_on_rcs_skipped": 36,
  "bot_suspect": false,
  "list_id": "3f0c9a2e-5b1d-4c7e-9a44-6d2f0e8b1c73",
  "list_exists": true
}

The reasons:

Treat an unknown reason as other: more may be added.

Remove numbers not on RCS from the list

http
POST /api/v1/rcs/broadcasts/{id}/remove-not-on-rcs?cursor={cursor}

Deletes, from the contact list the broadcast used, the numbers whose message failed as not on RCS (the not_on_rcs reason above). Other lists keep them. Owners and operators only, from a signed-in panel session: an API key gets 403 api_key_endpoint_not_allowed.

One call reads up to 1,00,000 recipients, or about 25 seconds of them, and removes what it found:

json
{
  "success": true,
  "removed": 412,
  "checked": 100000,
  "done": false,
  "next_cursor": "AAIAAABkAAAAEw"
}

Running it again is safe: numbers already removed are skipped. The list's member count goes down by removed, and each call that removed numbers is recorded in the audit log.

Button taps

http
GET /api/v1/rcs/broadcasts/{id}/button-taps

How many times each button in the broadcast was tapped. Every tap counts, so one person who taps twice counts twice. clicked_count on the broadcast counts people, once each, and stays the CTR figure. Counts only: every role can call it, and so can an API key with broadcasts:read.

json
{
  "success": true,
  "total_taps": 1550,
  "buttons": [
    { "label": "Shop now", "taps": 1240 },
    { "label": "Call us",  "taps": 310 }
  ],
  "other_taps": 0,
  "other_buttons": 0
}

Taps on single messages sent with send message are not counted. A broadcast sent before this endpoint existed returns total_taps: 0.

Test send

Fire one broadcast-shaped message to your own phone before actually launching the broadcast. Bypasses billing entirely, see the test send section on Templates for the full endpoint schema.

Composer flow:

  1. On Broadcasts, press New broadcast, then pick a bot and an approved template.
  2. Click Send test to +91987…321 at the bottom left of step 2.
  3. The message lands on me.test_phone_number || me.phone. The wallet is not touched; the broadcast's sent_count does not move.
http
POST /api/v1/rcs/test-send
{ "bot_id": "<uuid>", "template_id": "<uuid>" }
The New broadcast composer on step 2, Message, with the step bar Setup, Message and Audience & send at the top, the template diwali_early_access picked and a live preview of its Diwali Edit card, the Send test to +91987…321 button at the bottom left, and a green note at the top right reading Test message sent. Check your phone in a few seconds. Sent to +919876554321
Pick a template, then press Send test. The note shows the number the test went to.

Response:

json
{ "success": true, "test_send_id": "…", "msg_id": "…", "phone": "+919876543210" }

Status transitions arrive on the SSE stream as test_send.status events, and the composer's history endpoint is GET /api/v1/rcs/test-sends?limit=20. Full schema on the templates page.

Opt-out filter

Every broadcast filters recipients through the account's opt-out list at prep time. Matches never enter the send pool, and the broadcast row surfaces the count:

json
{
  "broadcast_id": "…",
  "total_count": 99923,
  "sent_count": 99923,
  "optout_skipped_count": 77
}

The filter is a snapshot at prep time, opt-outs added while a broadcast is running do not retro-actively skip queued targets.

POST /api/v1/rcs/messages/send also rejects with a 403 recipient_opted_out when the recipient is on the caller's list.

Reachability filter

Who a broadcast sends to depends on its audience. The answers that count come from the list's reachability check, whichever of your bots made it, and apply to broadcasts from every bot on your account. While a check runs, and after one fails or stops part way, the answers from the check before it still count, together with the answers the new check has saved. A check is optional and never blocks a send.

With rcs:

Only a bot that supports number checks can run a check, but a broadcast from any other bot on your account skips the same numbers. A list never checked goes to every number except the people who opted out (and, with rcs, the 30-day skips). A number that cannot get RCS then fails, shows in failed_count with its reason on Targets, and is not charged. The same holds for every number all sends to.

The 30-day skip belongs to one bot and applies only to rcs. A number is remembered only when the broadcast it failed on delivered at least one message, and another failure on the same bot starts the 30 days again. Your other bots still send to it. Single messages from send message and test sends are not skipped and do not add numbers to it.

Skipped numbers are not messaged and not charged, and the broadcast row counts them:

json
{
  "broadcast_id": "…",
  "total_count": 1008,
  "optout_skipped_count": 12,
  "unreachable_skipped_count": 180
}

Like the opt-out filter, it is applied when the recipients are prepared, with the answers saved at that moment. An audience that reaches nobody is refused at Create and Start with no_reachable_recipients.

A/B testing

Set ab_test: true in the create body to run the broadcast as an A/B test. Each recipient is put in a fixed 0 to 99 slot and gets variant "A" or "B" by ab_split_ratio. Each variant sends its own template and keeps its own counters, which GET /rcs/broadcasts/{id} returns in an ab block.

Create body

http
POST /api/v1/rcs/broadcasts
{
  "name":            "May launch, A/B",
  "bot_id":          "3c9…",
  "list_id":         "9ff…",

  "ab_test":         true,
  "ab_template_a":   "48b…",
  "ab_template_b":   "7de…",
  "ab_split_ratio":  50
}

When ab_test is true, template_id is optional and, if supplied, ignored, ab_template_a becomes the canonical template on the broadcast row. Both templates must be effectively approved; an un-approved variant returns 403 template_not_approved.

Detail response

json
{
  "success": true,
  "broadcast": {
    "broadcast_id": "…",
    "ab_test": true,
    "ab": {
      "split_ratio": 50,
      "variant_a": {
        "template_id": "48b…", "template_name": "Launch v1",
        "sent": 5000, "delivered": 4880, "read": 3120,
        "clicked": 620, "failed": 12,
        "ctr": 12.7
      },
      "variant_b": {
        "template_id": "7de…", "template_name": "Launch v2",
        "sent": 5000, "delivered": 4901, "read": 3245,
        "clicked": 785, "failed": 8,
        "ctr": 16.0
      },
      "winner": "B",
      "confidence": "significant"
    }
  }
}

confidence

  • insufficient_data, fewer than 500 combined clicks (or either arm has 0 delivered).
  • significant, Pearson two-proportion chi-square ≥ 3.841 (95% one- tail, df=1).
  • not_significant, chi-square below the threshold.

Deterministic hashing

Bucketing is fnv32(phone) % 100 < ab_split_ratio → variant A, otherwise B. The same phone always lands on the same variant across retargeting from either arm, no split-brain if you rebuild the list.

SSE

broadcast.ab_result fires once when the broadcast completes:

json
{
  "type": "broadcast.ab_result",
  "data": {
    "broadcast_id": "…",
    "winner": "B",
    "confidence": "significant"
  }
}

Retargeting

Turn any subset of a broadcast's recipients into a fresh contact list, ready to feed straight back into a new broadcast.

http
POST /api/v1/rcs/broadcasts/{id}/retarget
{
  "subset":         "clickers",
  "new_list_name":  "May clickers"
}

Subsets

Response

json
{
  "success":              true,
  "new_list_id":          "b3c…",
  "new_list_name":        "May clickers",
  "member_count":         620,
  "dropped_optout_count": 4
}

Notes

  • Opt-outs are honoured: phones on your opt-out list are left out and counted in dropped_optout_count.
  • Without new_list_name, the list is named Retarget: <broadcast name>: <subset>.
  • The new list is an ordinary contact list, so it's editable via the standard contact-list endpoints.
  • Member rows carry extra.source = "retarget" and extra.source_broadcast_id.
  • Retarget only builds a list, so the daily spend limit does not refuse it.

When nobody matches, it answers HTTP 400 and makes no list:

json
{
  "success": false,
  "code": "no_recipients",
  "message": "No recipients matched this subset. Nothing to retarget.",
  "dropped_optout_count": 0
}

An unknown subset is 400 with the message subset must be one of clickers | read_not_clicked | delivered_not_read | didnt_read | didnt_open | failed | reachable_only | custom. A read of the recipients that fails is 503 targets_unavailable.

Panel UX

A running or completed broadcast's page has a Retarget button. It offers four presets, Clicked (clickers), Read, no click (read_not_clicked), Delivered, not read (delivered_not_read) and Failed (failed), greys out a preset nobody is in, then drops you into a new broadcast with the fresh list already selected.

The Retarget this audience dialog for the completed broadcast Diwali offers, with the presets Clicked (1,318 people, picked), Read, no click, Delivered, not read and Failed (640 numbers), the New list name Retarget: Diwali offers: Clicked, and the Create list button
Pick a preset, then Create list. The new broadcast opens with that list.

Recurring broadcasts

See the dedicated Recurring broadcasts reference for the cron schedule and how each run becomes a broadcast. A recurring definition stores an audience too, and each run copies it to the broadcast it makes and counts the list again.