WhatsApp

WhatsApp broadcasts

Send an approved template to a list of contacts with per-person variables, now or later, and track who received and read it.

A broadcast sends one approved template to many people, each as a private one-to-one message with their own name, order number or code filled in. Use it for campaigns, reminders and announcements. Pozy queues the sends, tracks each recipient through sent, delivered and read, and puts any replies in the inbox.

Broadcasts work the same way on other messaging channels; the Broadcasts guide covers the shared parts. This page covers what is specific to WhatsApp.

#Before you send

Only message people who opted in

WhatsApp requires that every recipient has agreed to hear from your business on WhatsApp. Sending to people who did not opt in leads to blocks and reports, which lower your number's quality rating and can get templates paused or the number restricted. Keep isSubscribed accurate on your contacts and filter on it.

Three limits shape a WhatsApp broadcast:

Limit What happens
Messaging limit tier Meta caps the unique people a number can reach per day. A new number is on TIER_250. Once the cap is reached Meta stops delivering, so a list bigger than the tier will not all arrive. Check messaging_limit_tier with number info before a large send.
Quality rating A RED rating can pause templates and lower the tier. Watch whatsapp.account.quality_updated.
Throughput A coexistence number sends at most 20 messages per second. Cloud API-only numbers follow Meta's standard throughput.

Each recipient counts as one outbound message on your Pozy bill. Meta also charges its own per-template fee to your WABA (Pricing).

#Send a broadcast

#Create the draft

Call POST /v1/broadcasts with platform: "whatsapp", the profile and account, a name for your own reference and the template to send.

curl -X POST https://api.pozy.ai/v1/broadcasts \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "6710c4e2b9a1f03d8e5c7a21",
    "accountId": "6712a9d4c0e3b58f1a7d2e64",
    "platform": "whatsapp",
    "name": "November loyalty offer",
    "template": {
      "name": "loyalty_offer",
      "language": "en",
      "components": [{
        "type": "body",
        "parameters": [
          { "type": "text", "text": "{{1}}" },
          { "type": "text", "text": "{{2}}" }
        ]
      }],
      "variableMapping": {
        "1": { "field": "name" },
        "2": { "field": "custom", "customValue": "BREAD10" }
      }
    },
    "segmentFilters": { "tags": ["loyalty"], "isSubscribed": true }
  }'

A template without variables only needs name and language.

#Add recipients

Call POST /v1/broadcasts/{broadcastId}/recipients with one of:

Field Adds
phones Numbers in E.164 (+351912345678). Pozy creates a contact for any number it has not seen.
contactIds Existing Pozy contacts, by contact id
useSegment: true Every contact matching the broadcast's segmentFilters
cURL
curl -X POST "https://api.pozy.ai/v1/broadcasts/$BROADCAST_ID/recipients" \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "useSegment": true }'

The response says how many were added and how many were skipped (duplicates, and contacts with no WhatsApp channel).

#Send now or later

Start right away with POST /v1/broadcasts/{broadcastId}/send, or pick a time with POST /v1/broadcasts/{broadcastId}/schedule and an ISO 8601 scheduledAt:

cURL
curl -X POST "https://api.pozy.ai/v1/broadcasts/$BROADCAST_ID/schedule" \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scheduledAt": "2026-11-05T09:30:00Z" }'

A scheduled broadcast can be stopped with POST /v1/broadcasts/{broadcastId}/cancel before it starts.

#Fill variables per recipient

variableMapping maps each numbered variable of the template body to a value. Pozy resolves it for every recipient at send time.

field Becomes
name The contact's name, or "there" if it is empty
phone The recipient's phone number
email The contact's email
company The contact's company
custom The fixed customValue you set, the same for everyone

Broadcasts fill numbered variables ({{1}}, {{2}}) only, not named ones. The number of variableMapping entries must match the number of variables in the template body exactly. If it does not, Meta rejects each send with code 132000 and every recipient fails.

segmentFilters.customFields matches contact custom fields by slug, and the type must match too: 5 does not match "5".

#Track delivery

Each recipient moves through pending, sent, delivered and read, or ends at failed. Two ways to follow along:

Or subscribe to message.delivered, message.read and message.failed and update your own records as events arrive.

Replies come in as normal conversations. Because the customer wrote back, the 24-hour window is open and you can answer with free-form messages.

#Common errors

Error Cause Fix
400 "Broadcast has no recipients" on send or schedule Nothing was added Add recipients first
400 "Cannot send broadcast in sending status" The broadcast already started or finished Check status before retrying
Many recipients failed with 132000 Variable count does not match the template Fix variableMapping and create a new broadcast
Far fewer deliveries than recipients on a large list The number's messaging limit tier was reached Wait for Meta to raise the tier, or spread the list over several days

#Endpoints

Endpoint What it does
GET /v1/broadcasts List broadcasts
POST /v1/broadcasts Create broadcast draft
GET /v1/broadcasts/{broadcastId} Get broadcast details
PATCH /v1/broadcasts/{broadcastId} Update broadcast
DELETE /v1/broadcasts/{broadcastId} Delete broadcast
POST /v1/broadcasts/{broadcastId}/send Send broadcast now
POST /v1/broadcasts/{broadcastId}/schedule Schedule broadcast for later
POST /v1/broadcasts/{broadcastId}/cancel Cancel broadcast
GET /v1/broadcasts/{broadcastId}/recipients List broadcast recipients
POST /v1/broadcasts/{broadcastId}/recipients Add recipients to a broadcast

#Webhook events

Event When it fires
message.sent Message sent.
message.delivered Message delivered.
message.read Message read.
message.failed Message delivery failed.
whatsapp.account.quality_updated WhatsApp quality rating or messaging limit changed.