Sign inGet started

Get a broadcast

GET
/v1/email/broadcasts/{broadcast_id}
const broadcast = await bird.broadcasts.get("eb_01krdgeqcxet5s7t44vh8rt9mg");
console.log(broadcast.status, broadcast.sent_count, broadcast.delivered_count);
Response200
{
  "id": "eb_01krdgeqcxet5s7t44vh8rt9mg",
  "from": {
    "email": "jane@acme.com",
    "name": "Jane Doe"
  },
  "audience_id": "adn_01krdgeqcxet5s7t44vh8rt9mg",
  "template": {
    "id": "emt_01krdgeqcxet5s7t44vh8rt9mg",
    "version_id": "emv_01krdgeqcxet5s7t44vh8rt9mg"
  },
  "html_bytes": 18432,
  "text_bytes": 2104,
  "category": "marketing",
  "reply_to": [
    {
      "email": "jane@acme.com",
      "name": "Jane Doe"
    }
  ],
  "status": "sent",
  "next": [
    {
      "kind": "operation"
    }
  ],
  "failure_reason": null,
  "failure_detail": null,
  "recipient_count": 4820,
  "sent_count": 4820,
  "delivered_count": 4712,
  "bounced_count": 96,
  "complained_count": 12,
  "open_count": 3104,
  "click_count": 812,
  "sending_ips": [
    "198.51.100.42"
  ],
  "unique_opens_non_prefetched": 2140,
  "unique_clicks": 693,
  "out_of_band_bounces": 14,
  "delivered_recipients": 4724,
  "tags": [
    {
      "name": "category",
      "value": "welcome"
    }
  ],
  "track_opens": true,
  "track_clicks": true,
  "created_at": "2026-09-01T09:14:02.418Z",
  "scheduled_at": "2026-09-02T08:00:00Z",
  "started_at": "2026-09-02T08:00:03.771Z",
  "sent_at": "2026-09-02T08:11:47.902Z"
}
Returns one broadcast, with its audience reference and counters.
The full recipient list, with each recipient's own delivery status, is paginated separately: see List recipients of a broadcast.
Parameters
broadcast_id
string
Broadcast identifier. Starts with eb_.
Response Payload
id
string
required
Broadcast ID.
from
object
The address this broadcast sends from. name is filled in when the broadcast was given a display name to send under. Left out on a draft that has not picked a sender yet.
Show child attributes
from.email
string
required
Email address.
from.name
string
Display name shown alongside the address in mail clients.
audience_id
string
The audience this broadcast sends to. When the send starts we turn the audience into a list of recipients, and you can read that list a page at a time with List recipients of a broadcast. Left out on a draft that has not picked an audience yet.
template
nullable object
The template this broadcast sends. A broadcast sends the template's published version, and the exact version is fixed when the broadcast is prepared for sending, so publishing a new version afterwards does not change what this broadcast sends. Null on a draft that has not chosen a template yet.
Show child attributes
template.id
string
required
Which template the broadcast sends. Which version of it the send is fixed to is version_id.
template.version_id
nullable string
The template version this broadcast is fixed to. It is chosen when the broadcast is prepared for sending, so publishing a new version while the broadcast is going out cannot change what the rest of the recipients get. Null until the broadcast is prepared.
html_bytes
integer
Size of the HTML body this broadcast sends, in bytes, or 0 when its content has no HTML part. Measured on the template version the broadcast sends, so this is the real body we send and differs per recipient only by that recipient's own merge values. Returned on a single broadcast read, and absent from the list and from the broadcast that creating, updating, sending or canceling one returns, none of which measure the content. Absent too when the broadcast has no template or its content can no longer be read.
text_bytes
integer
Size of the plain-text body this broadcast sends, in bytes, or 0 when its content has no plain-text part. Measured, and absent, the same way as html_bytes.
category
string
required
What kind of email this is, which decides how suppressions apply to it. A marketing broadcast is held back from every suppressed address. A transactional one still goes to addresses suppressed for a complaint or an unsubscribe, because those suppressions are about marketing mail.
Possible values: marketing, transactional
ip_pool_id
string
The IP pool this broadcast sends from, or ipp_shared when it sends through the shared pool. Absent when it sends on your organization's default pool.
reply_to
array of object
Where replies to this broadcast go, if you want them somewhere other than the from address. Absent when you have not set one.
Show child attributes
reply_to.email
string
required
Email address.
reply_to.name
string
Display name shown alongside the address in mail clients.
headers
object
Any custom email headers set on the broadcast. Returned on a single broadcast read and on the broadcast that creating, updating, sending or canceling one returns, and absent from the list. The unsubscribe headers we add ourselves are not included.
status
string
required
Where the broadcast itself has got to, separate from what happened to individual recipients: for that, read sent_count, delivered_count, bounced_count and complained_count below. When it is failed, failure_reason says why.
next
array of object
What to do next about this broadcast, given the state it is in. Each entry names one action and says why it is worth taking. Present on reads that compute it: an empty list means there is nothing to do, and the field is absent entirely on responses that do not report next actions.
Show child attributes
next.kind
string
required
What you do about this step.
  • operation: call the operation named in operation, then read again.
  • external: act somewhere this API does not reach, then read again.
  • wait: nothing is asked of you, so read again later.
  • terminal: nothing you do resolves this, so stop retrying.
Tolerate a value you do not recognize: show the description and offer no action.
Possible values (may grow over time): operation, external, wait, terminal
next.description
string
required
A short, human-readable label for the step, suitable for display.
next.operation
string
The operationId to call. Present only when kind is operation. The operation's own schema says how to call it; this says only which one, and what to address it with.
next.params
object
The parameters that address the operation, by name: {"sender_id": "…"} for an operation on /v1/sms/senders/{sender_id}/requirements. A parameter the operation takes in its query string is given the same way, so an operation addressed as ?subject_id= carries {"subject_id": "…"}. Every parameter the call needs is here, whether its value came from the thing you were acting on or is fixed for this step, so you can make the call from this object alone. Present only when kind is operation and the operation names a subject. A request body, when the operation takes one, is described by the operation's own schema and never appears here.
next.url
string
A URL to open. Present only when kind is external, and only when the step has one. An external step whose description says to go and do something with no URL to open is normal.
failure_reason
nullable string
Why the broadcast failed. Set when status is failed, and null the rest of the time.
  • empty_audience: There was nobody to send to. Either the audience has no members, or every address in it is suppressed.
  • audience_unavailable: The audience no longer exists, so there was nothing to resolve.
  • content_invalid: The broadcast could not be set up to send. failure_detail says exactly what was wrong. It is one of these:
    • The broadcast has no template, or its template has been deleted.
    • The template has no published version, or no sendable content.
    • The template uses a loop that a broadcast cannot fill.
    • The template requires every send to name a language.
    • The sending domain is no longer verified.
    • The IP pool has nothing to send from.
    • The message could not be handed off for delivery.
  • insufficient_funds: There was not enough in the workspace balance to pay for the send.
  • quota_exceeded: The send would have gone past your organization's daily or monthly email allowance, whichever runs out first. This can happen when the broadcast is being prepared, or partway through sending if the remaining recipients no longer fit. failure_detail gives you the count and the limit.
  • internal_error: Something went wrong on our side. Retry, and open a support ticket if it keeps happening.
Possible values: empty_audience, audience_unavailable, content_invalid, insufficient_funds, quota_exceeded, internal_error, null
failure_detail
nullable string
A sentence explaining the failure in more detail than failure_reason does, and null when the broadcast has not failed. Show it to the person using your app. Do not write code that reads it, because the wording can change. Branch on failure_reason instead.
recipient_count
integer
required
Number of recipients after suppressed addresses are removed from the audience. This is 0 until sending starts and the audience becomes a recipient list.
sent_count
integer
How many recipients the broadcast has been sent to, counting every recipient whose status is processed or later. The number rises while the broadcast is sending and stops changing once the broadcast has finished. These counters are exact. The email stats endpoints report on the same sending but are approximate, so use these numbers when you need the precise count. Absent when the broadcast comes back from creating, updating, sending or canceling it, none of which read the counters. Absent from a list row for a broadcast that has no delivery events yet, such as a draft, where reading that one broadcast answers 0 instead. Absent too when the event store cannot be reached, which still returns 200. Read the broadcast again for the numbers.
delivered_count
integer
How many recipients' messages were accepted by their mail server. Absent when sent_count is.
bounced_count
integer
How many recipients the message could not be delivered to at all. Absent when sent_count is.
complained_count
integer
How many recipients marked the message as spam. Absent when sent_count is.
open_count
integer
How many times the message was opened, added up across every recipient. One recipient opening it twice counts twice. Absent when sent_count is.
click_count
integer
How many times a link in the message was clicked, added up across every recipient. One recipient clicking twice counts twice. Absent when sent_count is.
sending_ips
array of string
The IP addresses this broadcast's messages went out from, up to 100 of them. A broadcast is spread across every address in its pool, so more than one can appear. The receiving mail systems name the address when they deliver, bounce or defer a message, so this stays absent until the first of those comes back. Returned on a single broadcast read, and absent from the list and from the broadcast that creating, updating, sending or canceling one returns, none of which read them. For delivery and latency broken down per address, read the sending-IP stats.
unique_opens_non_prefetched
integer
How many distinct recipients opened the message at least once, excluding opens auto-fetched by inbox privacy features (such as Apple Mail Privacy Protection and the Gmail image proxy). A recipient who opened several times, or whose inbox prefetched the message, counts once. Absent when sent_count is.
unique_clicks
integer
How many distinct recipients clicked a link in the message at least once. A recipient who clicked several times counts once. Absent when sent_count is.
out_of_band_bounces
integer
How many recipients bounced after the message had already been accepted for delivery. A recipient who bounced this way more than once counts once. Absent when sent_count is.
delivered_recipients
integer
How many distinct recipients a delivery landed for. This is the denominator to measure unique_opens_non_prefetched, unique_clicks and complained_count against. It differs from delivered_count, which reports how many recipients are currently in the delivered state: a recipient who was delivered to and then complained moves to complained_count and leaves delivered_count, but stays here, because the message did reach them. Absent when sent_count is.
tags
array of object
Labels on this broadcast, each one a name and a value, that you can filter and search broadcasts by. Use tags for anything you want to find broadcasts by later, and metadata for data you only want handed back to you.
Show child attributes
tags.name
string
required
Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.
tags.value
string
required
Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.
metadata
object
Any JSON you want to keep on the broadcast. We store it and hand it back in webhook payloads, and that is all it does. If you want to search or filter by it, use tags instead.
track_opens
boolean
required
Whether opens are tracked for this broadcast.
track_clicks
boolean
required
Whether link clicks are tracked for this broadcast.
created_at
string
required
When the broadcast was created.
scheduled_at
string
When the broadcast is due to send, and absent when it is not scheduled.
started_at
string
When the broadcast started sending. Absent until then. Compare with sent_at, which is when the broadcast finished sending.
sent_at
nullable string
required
When the last recipient was sent to and the broadcast became sent. Null until then. Compare with started_at, which is when the broadcast started sending.
canceled_at
string
When the broadcast was canceled, and absent if it never was. This is when cancellation was requested, so it is set as soon as the status is canceling and does not move while the remaining sends stop and the status becomes canceled.