> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dairo.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Audiences & broadcasts

> Create an audience, add members by address or contact, and broadcast one email to every active member from a single inbox.

Group the people you email into an audience, then send to all of them with one
call. Dairo fans the broadcast out in the background and skips anyone who
previously reported your mail as spam. Audiences are built for opted-in
sending — onboarding cohorts, customer announcements, internal notices — not
cold outreach.

Reading audiences uses the `audiences:read` scope; creating, adding members, and
deleting use `audiences:write`. Sending a broadcast is a send like any other —
it needs `messages:send`.

## Create an audience

`POST /v1/audiences` takes a `name` (up to 120 characters) and an optional
`description`.

<CodeGroup>
  ```bash title="cURL" theme={null}
  curl -X POST https://api.dairo.app/v1/audiences \
    -H "Authorization: Bearer $DAIRO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "name": "Beta announcements" }'
  ```

  ```ts title="TypeScript" theme={null}
  const audience = await dairo.audiences.create({ name: "Beta announcements" });
  console.log(audience.list.id);
  ```

  ```python title="Python" theme={null}
  audience = dairo.audiences.create(name="Beta announcements")
  print(audience.list.id)
  ```

  ```text title="MCP" theme={null}
  Tool: manage_audiences  (scope audiences:write, confirm required)
  Args: { "action": "create", "name": "Beta announcements", "confirm": true }
  ```
</CodeGroup>

```json theme={null}
{
  "list": {
    "object": "audience",
    "id": "aud_123",
    "name": "Beta announcements",
    "status": "active",
    "memberCount": 0,
    "createdAt": "2026-06-12T10:00:00Z",
    "updatedAt": "2026-06-12T10:00:00Z"
  }
}
```

## Add members

`POST /v1/audiences/{audienceId}/members` takes up to 2,000 members per
request. Each member is exactly one of:

* a raw `handle` — an email address, with an optional `name`, or
* a `contactId` — a [contact](/contacts/contacts) whose primary email address
  becomes the member's address. An unknown contact is a `404`; a contact
  without an email handle is a `422`.

Members are upserted by address: re-adding someone updates their `name` and
`metadata` instead of creating a duplicate. The response reports how many
members the request imported.

<CodeGroup>
  ```bash title="cURL" theme={null}
  curl -X POST https://api.dairo.app/v1/audiences/aud_123/members \
    -H "Authorization: Bearer $DAIRO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "members": [ { "handle": "ada@example.com", "name": "Ada Lovelace" } ] }'
  ```

  ```ts title="TypeScript" theme={null}
  await dairo.audiences.addMembers("aud_123", {
    members: [{ handle: "ada@example.com", name: "Ada Lovelace" }],
  });
  ```

  ```python title="Python" theme={null}
  dairo.audiences.add_members(
      "aud_123",
      [{"handle": "ada@example.com", "name": "Ada Lovelace"}],
  )
  ```

  ```text title="MCP" theme={null}
  Tool: manage_audiences  (scope audiences:write, confirm required)
  Args: { "action": "addMembers", "audienceId": "aud_123", "members": [ { "handle": "ada@example.com", "name": "Ada Lovelace" } ], "confirm": true }
  ```
</CodeGroup>

```json theme={null}
{ "audienceId": "aud_123", "imported": 1 }
```

## Inspect an audience

List your audiences with `GET /v1/audiences`, or fetch one to see its active
members.

<CodeGroup>
  ```bash title="cURL" theme={null}
  curl https://api.dairo.app/v1/audiences \
    -H "Authorization: Bearer $DAIRO_API_KEY"

  curl https://api.dairo.app/v1/audiences/aud_123 \
    -H "Authorization: Bearer $DAIRO_API_KEY"
  ```

  ```ts title="TypeScript" theme={null}
  const audiences = await dairo.audiences.list();
  const detail = await dairo.audiences.get("aud_123");
  console.log(detail.members.length);
  ```

  ```python title="Python" theme={null}
  audiences = dairo.audiences.list()
  detail = dairo.audiences.get("aud_123")
  print(len(detail.members))
  ```
</CodeGroup>

## Send a broadcast

`POST /v1/audiences/{audienceId}/send` emails every active member from the
inbox you name. The body takes the same `inboxId`, `subject`, body, and
`attachments` fields as a single [send](/sending/sending-email) — exactly one of
`text`, `html`, `react`, or a stored `template` — but no `to`, because the
recipients come from the audience. Scheduling (`sendAt`), `replyTo`, custom
`headers`, and `tags` are not available on broadcasts.

A broadcast is asynchronous. Dairo validates the request and pins the message
once — a stored template resolves at submit, so a bad template or variable is a
`400` now, not a failure mid-fan-out — then returns `202` and delivers to each
member in the background:

```json theme={null}
{
  "object": "broadcast",
  "id": "bcast_9f8c2a1b4e7d",
  "audienceId": "aud_123",
  "status": "queued"
}
```

Each member's delivery becomes its own outbound message, so bounces and
complaints surface per recipient in [delivery tracking](/sending/outbound-tracking).

<CodeGroup>
  ```bash title="cURL" theme={null}
  curl -X POST https://api.dairo.app/v1/audiences/aud_123/send \
    -H "Authorization: Bearer $DAIRO_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: beta-open-2026-06" \
    -d '{
          "inboxId": "inbox_7c9e6679",
          "subject": "We are opening the beta",
          "html": "<p>You are in. Here is how to get started…</p>"
        }'
  ```

  ```ts title="TypeScript" theme={null}
  const result = await dairo.audiences.send("aud_123", {
    inboxId: "inbox_7c9e6679",
    subject: "We are opening the beta",
    html: "<p>You are in. Here is how to get started…</p>",
    idempotencyKey: "beta-open-2026-06",
  });
  console.log(result.audienceId);
  ```

  ```python title="Python" theme={null}
  result = dairo.audiences.send(
      "aud_123",
      inbox_id="inbox_7c9e6679",
      subject="We are opening the beta",
      html="<p>You are in. Here is how to get started…</p>",
      idempotency_key="beta-open-2026-06",
  )
  print(result.audience_id)
  ```

  ```text title="MCP" theme={null}
  Tool: send_broadcast  (scope messages:send)
  Args: { "action": "send", "audienceId": "aud_123", "inboxId": "inbox_7c9e6679", "subject": "We are opening the beta", "html": "…" }
  ```
</CodeGroup>

<Warning>
  **Members who reported your mail as spam are skipped.** Every broadcast leaves
  them out by default, which protects your sender reputation; they are only
  contacted if you deliberately pass `ignoreComplaints: true`. See
  [Land in the inbox](/webhooks/deliverability).
</Warning>

<Note>
  Retrying a broadcast is safe. A re-sent request with the same
  `Idempotency-Key` — or an identical request with no key at all — de-duplicates
  per recipient instead of emailing the whole audience twice. To deliberately send
  the same content to the same audience again, pass a new key. See
  [Retries & idempotency](/concepts/idempotency).
</Note>

## Delete an audience

Deleting an audience archives it so it can no longer be sent to.

<CodeGroup>
  ```bash title="cURL" theme={null}
  curl -X DELETE https://api.dairo.app/v1/audiences/aud_123 \
    -H "Authorization: Bearer $DAIRO_API_KEY"
  ```

  ```ts title="TypeScript" theme={null}
  await dairo.audiences.delete("aud_123");
  ```

  ```python title="Python" theme={null}
  dairo.audiences.delete("aud_123")
  ```
</CodeGroup>

## Send responsibly

* **Only add people who opted in.** Importing scraped or purchased addresses
  generates spam complaints and damages your domain's reputation for every
  inbox you send from.
* **Review the copy before a large send.** Especially for agent-written copy,
  have a person read the message before it goes to everyone.
* **Prune addresses that keep bouncing.** Watch each broadcast's bounces in
  delivery tracking and remove repeat offenders to keep the audience healthy.

## Next steps

* [Templates](/templates/templates) — write one email and reuse it across every broadcast.
* [Webhooks](/webhooks/webhooks) — get per-recipient delivery events pushed to your app.
* [API reference](/api-reference) — every audiences endpoint, with copy-paste requests.
