Skip to main content
A broadcast sends one approved marketing template to a saved segment or an explicit list of phone numbers. LazyApp creates the campaign, resolves the audience, paces sends to your number’s Meta messaging tier, and tracks delivery through to read receipts.
Broadcasts in live mode count against your plan’s monthly sends: 2,000 on Starter, 15,000 on Growth and 1,00,000 (fair use) on Pro. Test mode is never limited. See Monthly broadcast sends and Plans and limits.

Quick start

LazyApp uses one create call with recipients inline — you can still add more recipients to a draft or scheduled broadcast later.
The create response includes uuid, status, and stats. Poll GET /v1/broadcasts/{uuid} while status is running, or subscribe to campaign.* webhooks.

Create fields

There is no profileId, accountId, or platform field — the API key already scopes the request to one workspace and mode (live / test).

Template variables

Pass static placeholder values, or personalise per contact:
  • String / string[] shorthand still means the same values for every recipient.
  • Object slots use source: static, contact_attribute (key), or contact_field (field such as phone_number, email, username).
  • Missing attributes become an empty string so Meta still gets the expected parameter count.
  • header fills a text header variable when the template has one.
  • header_media is the image, video or document for a media header: a public https URL or an uploaded media id. Carousel cards take theirs in features.cards[].header_media.
  • body is an ordered array matching {{1}}, {{2}}, … in the template body.
The number of body entries must match the template’s placeholder count. A mismatch makes Meta reject the send (parameter-count error). An image-header marketing template, such as an intake announcement:
The shape of variable_map is checked when you create the broadcast, so a misspelt source or a header_media that is not a string is a 422 now rather than a failed send for every recipient later.

Add recipients

Only draft or scheduled broadcasts. Existing recipient rows are kept; new numbers are merged and compliance-checked.

Recipients

Target either:
  1. phone_numbers — explicit E.164 list (+919812345670).
  2. contact_segment_uuid — a segment you created over the API or in the console. contact_segment_id (the integer id) also works.
Recipients must already exist as contacts in the workspace with granted marketing consent. Numbers that are not contacts, or contacts without consent, are counted in stats.excluded with a reason — they are never sent. Workflow for a cold list:
To target everyone with a tag, create a segment filtering on the tag name and pass its uuid as contact_segment_uuid.

Scheduling

Set schedule_at on create and omit start (or pass "start": false):
The broadcast stays scheduled until LazyApp’s scheduler starts it at schedule_at, or you call POST /v1/broadcasts/{uuid}/start early. There is no separate POST …/schedule endpoint — scheduling is a field on create.

Compliance is enforced at send time, not create time

This is deliberate. A broadcast created on Monday and sent on Friday respects the opt-outs that happened on Wednesday.

Opt-outs

Suppressed contacts are excluded. There is no override.

Frequency caps

frequency_cap_days skips anyone who already received a marketing message inside that window.

Quiet hours

Sending pauses during quiet hours in the contact’s timezone and resumes after.

Messaging limits

Sends are paced to your number’s Meta messaging tier rather than being rejected in bulk.

Exclusion reasons

When you start a broadcast, stats breaks down the audience: Excluded recipients are stored with a reason code (visible in the console). Common codes: Broadcasts refuse recipients without granted marketing consent. Consent collected on your own website — a checkbox, a form, a CRM export — can be recorded with:
Consent is evidence, not just a flag — consent_text, proof_reference and captured_by are stored exactly as given. Granting marketing consent also lifts a matching suppression, so someone who just opted in on your site is not still opted out.

Monthly broadcast sends

Your plan sets how many live-mode broadcast recipients you can send to in a calendar month (UTC): Every recipient that is queued or sent counts, across all broadcasts in the workspace. The count resets on the 1st of the month. Test mode is never limited, so you can rehearse a broadcast on the test number as often as you like.
  • Starting checks the whole audience. If a broadcast has more pending recipients than you have sends left this month, LazyApp refuses to start it, and the message says how many sends remain and when they reset. Send to fewer people or move to a bigger plan in Billing. Over the API, the start call returns 422 with that reason in message.
  • A scheduled broadcast that no longer fits fails. It moves to failed with the reason, rather than retrying every minute.
  • A running broadcast pauses when the month is used up. Other broadcasts can use sends after this one started, so LazyApp checks again before each batch. When nothing is left, the broadcast moves to paused and your billing contacts get an email. Start it again next month, or after you upgrade, from the console or with POST /v1/broadcasts/{uuid}/start.

What a broadcast costs

The send limit is what your plan includes. The messages themselves are billed by Meta, at Meta’s rates, to your own Meta payment method. LazyApp adds 0%. See How Meta bills your messages and WhatsApp rates.

Status and webhooks

Webhook events: Per-message delivery still arrives on the usual message.* events for each recipient.
Marketing templates need an opt-in you can evidence. Broadcasting to a purchased list is the fastest route to having your number’s quality rating cut and your messaging limit reduced.

What we skip (Zernio-style)