Audiences & contacts

Clean lists, built in.

Set up in:

Store your contacts once, unique by email, and group them into audiences you target from a broadcast. A typed property registry keeps your data clean, and a 1,000-row batch upsert gets a list in fast.

welcome.tsx
200 · 1.2s
import { BirdClient } from "@messagebird/sdk";
import { render } from "@react-email/render";
import { WelcomeEmail } from "./emails/welcome";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

const { data, error } = await bird.email.send({
  from:    "Bird <hello@bird.com>",
  to:      ["ada@example.com"],
  subject: "Your invite is ready",
  html:    await render(<WelcomeEmail name="Ada" />),
}).safe();

if (error) throw error;
console.log(data.id);
// → "em_2bX91Yk8h..."

One contact record. Attributes that don't drift.

Audiences are part of the Bird Email API: a contact is unique by email and shared across your audiences, an audience is just a set of those contacts, and attributes always live on the contact, not copied onto every list. The property registry means a typo'd field is rejected at write time, not discovered in a campaign.

Five things that keep your data clean.

The data model does the bookkeeping, so your lists don't rot.

  1. 01

    One record per person.

    One contact per email, with first and last name, an external ID, and your own custom data.

  2. 02

    Audiences are membership.

    An audience is a set of contacts you add and remove freely. Attributes always live on the contact, never copied onto the list.

  3. 03

    Typed property registry.

    Define your custom fields up front: string, number, or boolean, with optional fallbacks. Unknown keys and wrong-typed values are rejected at write time.

  4. 04

    Batch upsert up to 1,000.

    Upsert up to 1,000 contacts in a single call, and join them to an audience in the same request.

  5. 05

    Exact-match lookup.

    Find a contact by exact email match, so your own systems can sync without scanning every record.

Get a whole list in with one call.

Upsert is idempotent on email, so re-running an import updates rather than duplicates. Add up to 1,000 contacts and join them to an audience in the same request, with no separate membership step and no de-dupe pass afterward. Larger lists go up in batches of 1,000. Each call is independent, so an interrupted import is safe to resume where it stopped.

import.ts
202
// Upsert up to 1,000 contacts and add them to an audience at once.
await bird.email.contacts.batchUpsert({
  audienceId: "aud_2bX91Yk8h",
  contacts: [
    { email: "ada@example.com",   firstName: "Ada",   data: { plan: "growth" } },
    { email: "grace@example.com", firstName: "Grace", data: { plan: "free" } },
  ],
});

Fields that can't drift.

Custom contact data goes through a typed registry. Declare each field once as a string, number, or boolean, with an optional fallback, and a typo'd key or wrong-typed value is rejected the moment you write it, not discovered halfway through a campaign. Because attributes live on the contact, not the list, moving someone between audiences never leaves a stale copy behind.

Works with the rest of Email.

Target the audiences you build here from a broadcast, and the same contacts receive transactional mail through the send API.

Audiences & contacts FAQ

Are contacts per-audience or global?+
Global. A contact is unique by email, and audiences just reference it. Move a contact between audiences and its attributes follow, because they live on the contact, not the list.
What is the property registry?+
A closed, typed schema for your custom contact fields. You declare each field's type (string, number, or boolean) with an optional fallback up front; unknown keys or wrong-typed values are rejected when you write them, so your data stays clean.
How do I import a list?+
Batch-upsert up to 1,000 contacts in one call, and join them to an audience in the same request, with no separate add step. Upsert is idempotent on email, so re-running an import updates rather than duplicates.
How do audiences relate to broadcasts?+
A broadcast targets a single audience. Build and maintain the audience here; reference it by ID when you send.

About 40% of the world's commercial email already runs on Bird.

Transactional and marketing email on infrastructure we've run for a decade. Audiences are one capability of the Bird Email API: sending, broadcasts, deliverability, suppression, and analytics ship with it.

Start with one channel.
Add the others when you're ready.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

Using Claude Code, Cursor, or Codex? Copy a setup prompt and your agent installs the Bird CLI and skills for you. Pick yours: