# Broadcasts

Send one message to many contacts at once, now or at a scheduled time, with per-recipient variables, segments and delivery tracking.

A broadcast sends one message from one account to a list of recipients: an order update to everyone who bought this week, a launch announcement to a tag, an event reminder to a segment. You create it as a draft, add recipients, then send it now or schedule it. Pozy tracks every recipient as sent, delivered, read or failed.

Broadcasts work on WhatsApp, SMS, iMessage, Instagram, Facebook, X, Bluesky and Slack. Telegram is coming soon. WhatsApp broadcasts send approved templates; the others send text.

## Create, fill and send

### Create the draft

```bash cURL
curl -X POST https://api.pozy.ai/v1/broadcasts \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "6650c1e2a3b4c5d6e7f80911",
    "accountId": "6650c1e2a3b4c5d6e7f80a44",
    "platform": "whatsapp",
    "name": "Black Friday early access",
    "template": {
      "name": "early_access",
      "language": "en",
      "components": [{ "type": "body", "parameters": [{ "type": "text", "text": "{{1}}" }, { "type": "text", "text": "{{2}}" }] }],
      "variableMapping": { "1": { "field": "name" }, "2": { "field": "custom", "customValue": "BF-EARLY-20" } }
    },
    "segmentFilters": { "tags": ["vip"], "isSubscribed": true }
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/broadcasts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    profileId: "6650c1e2a3b4c5d6e7f80911",
    accountId: "6650c1e2a3b4c5d6e7f80a44",
    platform: "whatsapp",
    name: "Black Friday early access",
    template: {
      name: "early_access",
      language: "en",
      components: [{ type: "body", parameters: [{ type: "text", text: "{{1}}" }, { type: "text", text: "{{2}}" }] }],
      variableMapping: { "1": { field: "name" }, "2": { field: "custom", customValue: "BF-EARLY-20" } },
    },
    segmentFilters: { tags: ["vip"], isSubscribed: true },
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
const broadcastId = data.broadcast.id;
```
```python Python
import os
import requests

H = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
created = requests.post(
    "https://api.pozy.ai/v1/broadcasts",
    headers=H,
    json={
        "profileId": "6650c1e2a3b4c5d6e7f80911",
        "accountId": "6650c1e2a3b4c5d6e7f80a44",
        "platform": "whatsapp",
        "name": "Black Friday early access",
        "template": {"name": "early_access", "language": "en", "variableMapping": {"1": {"field": "name"}}},
        "segmentFilters": {"tags": ["vip"], "isSubscribed": True},
    },
    timeout=30,
).json()
broadcast_id = created["broadcast"]["id"]
```

### Add recipients

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

- `useSegment: true` to add every contact matching `segmentFilters`
- `contactIds` with Pozy contact ids
- `phones` with E.164 numbers (WhatsApp, SMS). Pozy creates contacts for numbers it has not seen

```bash
curl -X POST https://api.pozy.ai/v1/broadcasts/6650c1e2a3b4c5d6e7f80a88/recipients \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "useSegment": true }'
```

The response counts `added` and `skipped`. Duplicates and contacts with no channel on this account are skipped. Call it several times to combine sources.

### Send or schedule

- `POST /v1/broadcasts/{id}/send` starts delivery now.
- `POST /v1/broadcasts/{id}/schedule` with `scheduledAt` (ISO 8601, in the future) sends it later. Call it again to move the date.
- `POST /v1/broadcasts/{id}/cancel` stops a scheduled broadcast.

## Messages and templates

| Platform | What to send |
| --- | --- |
| WhatsApp | `template` with an approved template's `name` and `language`, plus `components` and `variableMapping` when it has placeholders |
| SMS | `message.text`, and optionally `message.attachments` for MMS media (JPEG, PNG, GIF, WEBP, MP4 or 3GPP, public URLs, about 1 MB in total) |
| Everything else | `message.text` |

`variableMapping` fills numbered placeholders (`{{1}}`, `{{2}}`) per recipient at send time:

| `field` | Becomes |
| --- | --- |
| `name` | The contact's name, or "there" when it is empty |
| `phone` | The recipient's number |
| `email`, `company` | The contact's email or company |
| `custom` | The fixed `customValue`, the same for everyone |

> **Placeholder counts must match:**
> 
> The number of `variableMapping` entries must equal the number of placeholders in the template body. A mismatch makes WhatsApp reject each send with a parameter-count error. Named placeholders are not supported; use numbered ones.

## Segments

`segmentFilters` describes who `useSegment` adds:

| Field | Matches |
| --- | --- |
| `tags` | Contacts with these tags |
| `isSubscribed` | `true` to leave out people who opted out |
| `customFields` | Exact custom field values by slug, type included (`5` does not match `"5"`). Every key must match |

Set `isSubscribed: true` on every marketing broadcast.

## Platform rules that cap delivery

- **WhatsApp messaging limits.** A number's tier caps how many unique people it can start conversations with per day. A newly connected number starts at 250 a day, and recipients above the cap do not deliver. Check the number's tier before a large send; see [WhatsApp phone numbers](https://pozy.ai/docs/whatsapp/phone-numbers).
- **Instagram and Facebook.** A broadcast only reaches people who messaged the account in the last 24 hours. Message tags are not usable: `HUMAN_AGENT` is for replies typed by a person, and the others were retired.
- **SMS in the US** needs a registered 10DLC campaign. See [10DLC](https://pozy.ai/docs/telephony/10dlc).
- **Costs.** Each recipient counts as one outbound message. WhatsApp template fees are charged by WhatsApp on top. See [WhatsApp pricing](https://pozy.ai/docs/whatsapp/pricing) and [Pricing](https://pozy.ai/docs/billing).

## Track results

`GET /v1/broadcasts/{id}` shows `status` (`draft`, `scheduled`, `sending`, `completed`, `failed`, `cancelled`) and the counters `recipientCount`, `sentCount`, `deliveredCount`, `readCount` and `failedCount`.

`GET /v1/broadcasts/{id}/recipients` lists each recipient with `status` (`pending`, `sent`, `delivered`, `read`, `failed`) and timestamps. Failed rows carry `error`, `errorCode` and `errorExplanation`. Filter with `status=failed` to see what went wrong.

Every message also arrives as `message.sent` with `sentVia: "broadcast"` and the `broadcastId`, followed by delivery and read events where the platform reports them.

## Errors

| Error | Cause |
| --- | --- |
| `400` "Broadcast has no recipients" | Send or schedule before adding recipients |
| `400` "Cannot send broadcast in ... status" | The broadcast is already sending or done. Check `status` |
| Per-recipient `failed` | Usually a template mismatch, an opted-out number or a number that is not on WhatsApp. The call itself still succeeds |

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/broadcasts`](https://pozy.ai/docs/api/listBroadcasts) | List broadcasts |
| [`POST /v1/broadcasts`](https://pozy.ai/docs/api/createBroadcast) | Create broadcast draft |
| [`GET /v1/broadcasts/{broadcastId}`](https://pozy.ai/docs/api/getBroadcast) | Get broadcast details |
| [`PATCH /v1/broadcasts/{broadcastId}`](https://pozy.ai/docs/api/updateBroadcast) | Update broadcast |
| [`DELETE /v1/broadcasts/{broadcastId}`](https://pozy.ai/docs/api/deleteBroadcast) | Delete broadcast |
| [`POST /v1/broadcasts/{broadcastId}/send`](https://pozy.ai/docs/api/sendBroadcast) | Send broadcast now |
| [`POST /v1/broadcasts/{broadcastId}/schedule`](https://pozy.ai/docs/api/scheduleBroadcast) | Schedule broadcast for later |
| [`POST /v1/broadcasts/{broadcastId}/cancel`](https://pozy.ai/docs/api/cancelBroadcast) | Cancel broadcast |
| [`GET /v1/broadcasts/{broadcastId}/recipients`](https://pozy.ai/docs/api/listBroadcastRecipients) | List broadcast recipients |
| [`POST /v1/broadcasts/{broadcastId}/recipients`](https://pozy.ai/docs/api/addBroadcastRecipients) | Add recipients to a broadcast |
