Send a batch of messages
POST
/v1/email/batches
Accepts up to 100 independent email messages and queues them for delivery. All items are validated before any are queued — if one fails validation, the entire batch is rejected. Field-level validation failures and business-rule failures (such as domain_not_verified or all_recipients_suppressed) both return 422.
Request Payload
Array of objects, each with:
from
string or object
required
Sender address, as a plain email string, an RFC 5322 mailbox string (Jane <jane@example.com>), or an object with an optional display name. Must be from a verified domain in this workspace.
to
array of string or object
required
Primary recipients. Each entry is a plain email string, an RFC 5322 mailbox string (Jane <jane@example.com>), or an object with an optional display name.
cc
array of string or object
CC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (Jane <jane@example.com>), or an object with an optional display name.
bcc
array of string or object
BCC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (Jane <jane@example.com>), or an object with an optional display name.
subject
string
required
Message subject line.
html
string
HTML body. At least one of html or text must be provided.
text
string
Plain-text body. At least one of html or text must be provided.
reply_to
array of string or object
Reply-To addresses, each a plain email string, an RFC 5322 mailbox string, or an object with an optional display name. RFC 5322 allows multiple. Every recipient reply hits all listed addresses, so 1-2 is typical; the 25 cap exists to prevent runaway header sizes that some MTAs reject.
headers
object
Custom email headers as key-value pairs.
tags
array of object
Structured {name, value} labels for filtering and analytics. Tags become first-class query dimensions: filter the list endpoint by tag name, slice analytics rollups by tag, and surface in webhook payloads. Cap: 20 tags per send. Use tags for low-cardinality dimensions (category, experiment_variant, template_id). For arbitrary structured context that you do not need as a filter dimension, use metadata instead.
Show child parameters
name
string
required
Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.
value
string
required
Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.
metadata
object
Arbitrary JSON object stored, returned on API reads, and echoed in webhook payloads. Path-queryable in analytics (e.g. filter on metadata.order_id) but not surfaced as a first-class dashboard filter dimension. Cap: 2 KB serialized. Use metadata for per-send context like internal IDs, foreign keys, and structured payloads you want round-tripped through events. For low-cardinality filterable labels, use tags instead.
track_opens
boolean
Whether to track open events for this message.
track_clicks
boolean
Whether to track click events for this message.
ip_pool
string
ID of the IP pool to send from (ipp_ prefix), or ipp_shared to route through the shared pool explicitly. Omit to use your organization's default pool. An unknown pool, or a pool with no dedicated IPs available to send from, is rejected with a 422.
category
string
Content classification — independent of which endpoint you use. Controls suppression policy: marketing blocks on all suppression reasons (use for marketing content); transactional allows delivery through complaint and unsubscribe suppressions (use for receipts, password resets, and similar operational messages). Default: transactional.
in_reply_to_message_id
string
Preview feature — threaded replies. Currently unavailable; supplying this field returns 422 unsupported_feature. When generally available, sets In-Reply-To and References headers automatically.
attachments
array of object
File attachments. Total message size (body + inline images + all attachments) capped at 20 MB post-base64. Raw file content should stay under ~15 MB to leave room after encoding. Sends with attachments cannot use POST /v1/emails/batch; use the single-send endpoint. See the EmailAttachment schema for the full field contract.
Show child parameters
filename
string
required
Filename shown to the recipient. Required.
content
string
required
Base64-encoded attachment bytes. Required. Counts against the 20 MB per-send wire cap.
path
string
Preview feature — provide a URL and Bird fetches the attachment for you. Currently unavailable. Use content instead. The schema currently requires content, so a request with only path is rejected with 422 for missing content; a request supplying both content and path is rejected with 422 unsupported_feature until this preview ships. When generally available: HTTPS-only, single redirect followed and re-validated, private IP ranges blocked, request timeout enforced, fetched content counts against the 20 MB per-send wire cap.
content_type
string
MIME type. Inferred from filename extension when omitted. Used to enforce the blocklist of disallowed executable / script types.
content_id
string
RFC 2392 Content-ID. When set, the attachment is rendered inline and can be referenced from the HTML body as <img src="cid:{content_id}"/>. When omitted, the attachment is rendered as a regular file attachment.
scheduled_at
string
Preview feature — send-later scheduling. Currently unavailable; supplying this field returns 422 unsupported_feature.
contact_id
string
Preview feature — contact-targeted sends. Currently unavailable; supplying this field returns 422 unsupported_feature.
topic_id
string
Preview feature — topic-gated sends. Currently unavailable; supplying this field returns 422 unsupported_feature. When generally available, a non-empty topic_id gates delivery on the recipient's opt-in state for that topic — if the recipient is opt_out, the send is silently suppressed and an email.suppressed event fires with reason: topic_opt_out.
Response Payload
data
array of object
required
One entry per message in the batch, in submission order.
Show child attributes
id
string
required
Message ID assigned to this batch item.
status
string
required
Initial status of this message in the batch.
category
string
required
Resolved category for this batch item.
cURL
curl -X POST "https://us1.platform.bird.com/v1/email/batches" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[
{
"from": "Acme <noreply@acme.com>",
"to": [
"jane@example.com"
],
"subject": "Your receipt for order #1234",
"text": "Thanks for your purchase! Your receipt is attached."
},
{
"from": "Acme <noreply@acme.com>",
"to": [
"john@example.com"
],
"subject": "Your receipt for order #1235",
"text": "Thanks for your purchase! Your receipt is attached."
}
]'