Documentation
Sign inGet started

Bulk sending: batches & broadcasts

This guide covers reaching many recipients: the batch endpoint, POST /v1/email/batches, and where audience-targeted broadcasts fit today. If you only ever send one message at a time, start with sending email instead.

When to use what

  • A handful of independent messages at once — use a batch. One request carries up to 100 complete message objects and saves you 100 round trips.
  • High-volume sending from your own loop — calling the single-send endpoint repeatedly is a perfectly good architecture; batches don't make a message cheaper or faster to deliver, they just amortize the HTTP overhead. The real volume lever is rate limits: batch requests draw from the email_batch rate-limit group, separate from the email_send group used by single sends, so batching raises how many messages you can hand over per unit of wall-clock time.
  • One message to a stored audience — that's a broadcast, covered below. Batches are not broadcasts: there is no shared content definition, no audience targeting, and no per-recipient personalization. Every message in a batch is a self-contained payload you assemble yourself.

Batch sends

POST /v1/email/batches takes a JSON array of 1–100 message objects. Each item is a complete, independent send request — its own from, to, subject, content, and optionally its own category, ip_pool, tags, and metadata. The item schema is exactly the single-send payload, so everything in sending email applies per item, including the category default of transactional.
Exemplo de código
curl -X POST https://us1.platform.bird.com/v1/email/batches \
  -H "Authorization: Bearer bk_us1_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: batch-2026-06-10-001" \
  -d '[
    {
      "from": "hello@yourdomain.com",
      "to": ["delivered@messagebird.dev"],
      "subject": "Your receipt",
      "html": "<p>Thanks for your order.</p>"
    },
    {
      "from": "hello@yourdomain.com",
      "to": ["delivered@messagebird.dev"],
      "subject": "June product news",
      "html": "<p>What shipped this month.</p>",
      "category": "marketing"
    },
    {
      "from": "alerts@yourdomain.com",
      "to": ["delivered@messagebird.dev"],
      "subject": "Usage threshold reached",
      "text": "You have used 80% of your quota."
    }
  ]'

All-or-nothing validation

Every item is validated before any item is queued. If one message fails — a field-level validation error or an unverified sender domain — the entire batch is rejected with a 422 and nothing is sent. A batch never partially succeeds at accept time, so you never have to work out which half of a failed request went through; fix the offending item and resubmit the whole array. Suppression is not checked at accept time: an item whose recipients are all suppressed still accepts and gets an em_ ID, and those recipients surface as status: rejected once the message is processed (see suppressions).

The 202 response

A successful batch returns 202 Accepted with one entry per message, in submission order:
Exemplo de código
{
  "data": [
    { "id": "em_019c1930687b7bfa...", "status": "accepted", "category": "transactional" },
    { "id": "em_019c1930687c4e21...", "status": "accepted", "category": "marketing" },
    { "id": "em_019c1930687d9b02...", "status": "accepted", "category": "transactional" }
  ]
}
Each child is a regular message from this point on: track it by its em_ ID through GET /v1/email/messages/{id}, its recipient and event endpoints, and webhooks — exactly as if it had been sent individually. The same async model applies: 202 means durably accepted, and per-recipient delivery outcomes arrive afterwards.

Idempotent retries

Send an Idempotency-Key header with the batch (as in the example above). If the request succeeded but you never saw the response, replaying it with the same key returns the original result — the same child message IDs, with an Idempotency-Replay header — instead of sending every message again. With up to 100 messages per request, the cost of an accidental duplicate is multiplied, so treat the key as required in production. See idempotency.

Attachments are not supported

Batch items cannot carry attachments — any item that includes them rejects the whole batch with a 422 (unsupported_feature, on the attachments field), the same error a single send returns. Attachments are a reserved field on the single-send endpoint too in v1; when they ship, they will be a single-send capability, not a batch one.

Broadcasts

A broadcast is one message sent to a stored audience — Bird resolves the audience's current members (minus suppressions) into the recipient set at send time, instead of you enumerating addresses. Today, audience broadcasts are available from the Bird dashboard; they are not yet part of the public API. The send and batch endpoints have no broadcast or audience fields, and the request body rejects unknown properties, so there is no way to address a broadcast from the API for now.
Until the broadcast API ships, the two API-side options for reaching many recipients are batch sends and fanning out over the single-send endpoint from your own loop. The public API reference will carry the broadcast operations once the surface lands.

Next steps

  • Sending email — the per-item payload in full: fields, limits, tags vs metadata
  • Categoriesmarketing vs transactional and what each does to suppression policy
  • Idempotency — key format, retention, and replay semantics
  • API reference — full batch request and response schemas