email-messages

Create an email message

Sends an email to the recipients you list explicitly in to/cc/bcc. Use it for transactional sends (receipts, password resets, alerts) and for marketing sends where you have the recipient addresses on hand. To submit many independent messages in one request, use Create a batch of email messages instead. The category field controls suppression policy independently of content: set it to marketing when sending marketing content.

The 202 response means the message is safely accepted and awaiting delivery. Fetch it by id or subscribe to webhook events to follow delivery. The request never half-succeeds: an unverified sender domain or any field-level validation failure rejects it immediately with a 422 naming the reason. Suppression is evaluated per recipient after acceptance, so a suppressed recipient appears as rejected on the message's recipient list rather than as a synchronous error. New workspaces can send from the shared onboarding domain before verifying their own. The quickstart covers its recipient and volume limits.

post/v1/email/messages

Request

  • Base URL: https://us1.platform.bird.com
  • URL: https://us1.platform.bird.com/v1/email/messages
  • Auth: one of:
    • HTTP bearer
    • API key in cookie bird_session

Headers

Idempotency-Keystring

Client-supplied key. On operations supporting request deduplication, a retained response is replayed for duplicate requests with the same key within the idempotency window (3 hours by default). This protection requires a workspace, organization, or staff-account scope. User-only and unscoped unauthenticated operations, streams, and operations with a separate replay contract do not use this response replay.

On a supported operation, if idempotency protection is unavailable before execution, the API returns 503 IdempotencyUnavailable (E01033) without executing this attempt. Retry with backoff using the same key and request. An operation that takes effect before its response is retained can still execute again on retry.

Two distinct 409 errors signal misuse:

  • request_in_progress (E01004): The same key is currently being processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
  • idempotency_key_reuse (E01005): The same key has already completed against a different request body or method. Generate a new key.

Recommended key format is <event-type>/<entity-id> (for example welcome-user/usr_abc123).

X-Workspace-Idstring

Workspace context for the request. Required for dashboard authentication and master keys. Workspace keys and access tokens already identify their workspace; send that workspace or omit the header. A different one is rejected.

X-Organization-Idstring

Organization context for the request. Required for dashboard authentication. An API key or access token carries its own organization, so send either that organization or no header at all; a different one is rejected.

Request body

subjectstring

Message subject line. Required for inline sends. Omit it when sending a template (the template supplies the subject).

htmlstring

HTML body. At least one of html or text must be provided.

textstring

Plain-text body. At least one of html or text must be provided.

headersobject

Custom email headers, such as References, In-Reply-To, and X-* headers. Reserved headers and values containing carriage returns or line feeds return 422. Set addressing and subject through their dedicated fields. Transactional sends accept List-Unsubscribe and List-Unsubscribe-Post. Marketing sends use Bird-managed unsubscribe by default.

metadataobject

Arbitrary JSON object returned on API reads and included in webhook payloads. You can query its paths in analytics, such as metadata.order_id, but it is not a dashboard filter. The serialized object is limited to 2 KB. Use metadata for per-send context such as order IDs, customer references, and structured event data. For low-cardinality filterable labels, use tags instead.

parametersobject

Parameter values used to personalize inline content, shared across all recipients of this send. Tokens such as {{ animal }} are replaced with matching values; missing values render empty. Include this object, even as {}, to use Liquid, or omit it to leave tokens unchanged. Use single-word names other than bird. Cap: 16 KB serialized. For a stored template, use template.parameters instead. See inline personalization for validation and URL encoding examples.

track_opensboolean

Whether to track open events for this message.

track_clicksboolean

Whether to track click events for this message.

ip_pool_idstring

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'marketing' | 'transactional'

Content classification, which controls suppression policy:

  • marketing: Blocks on all suppression reasons.
  • transactional: Allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail.
scheduled_atstring date-time

Schedule the message to send at a future time instead of immediately. Must be at least 30 seconds and at most 30 days ahead. Outside that range the request is rejected with 422. The message returns with status accepted and shows as scheduled on reads until it sends. Cancel it before then with the message cancel endpoint. Scheduled sends count against your plan's monthly scheduled-email allowance. Exceeding it is rejected with a 422. For a stored template, the published version, language and parameter values are pinned when we accept the request, so a later publication does not change what sends. If the template is deleted before the message is due, the message is rejected with generation_failure. We also check sender eligibility and send-volume allowance when the message is due. Batch items take this field too, so one batch can mix scheduled and immediate messages.

Example request

{
  "from": {
    "email": "noreply@acme.com",
    "name": "Acme Support"
  },
  "to": [
    {
      "email": "delivered@messagebird.dev",
      "name": "Jane Doe"
    }
  ],
  "cc": [
    "manager@acme.com"
  ],
  "reply_to": [
    "support@acme.com"
  ],
  "subject": "Welcome aboard",
  "html": "<h1>Hi there 👋</h1>",
  "text": "Hi there",
  "headers": {
    "X-Campaign": "spring-2026"
  },
  "tags": [
    {
      "name": "category",
      "value": "welcome"
    }
  ],
  "metadata": {
    "user_id": "usr_12345"
  },
  "category": "transactional",
  "track_clicks": false
}

Response

Message accepted for asynchronous delivery.

idstring required
subjectstring required

The subject line as delivered. For a send that used a template, the stored subject is the template's, so this reports it with the send's parameters substituted in, which is what the recipient saw.

category'marketing' | 'transactional' required

Content classification, which controls suppression policy:

  • marketing: Blocks on all suppression reasons.
  • transactional: Allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail.
status'scheduled' | 'accepted' | 'processed' | 'deferred' | 'delivered' | 'partial_failure' | 'bounced' | 'complained' | 'rejected' | 'canceled' required

Aggregate delivery status of an email, derived from its recipients' states.

In flight:

  • scheduled: The message is queued to send at a future time and has not been dispatched yet.
  • accepted: The initial status of an immediate send. The message is queued for its recipients.
  • processed: Delivery is underway, so at least one recipient's message is on its way out and none has failed.
  • deferred: At least one recipient's mailbox provider asked for a retry, and delivery attempts continue.

Final:

  • delivered: Every recipient's mail server accepted the message.
  • bounced: Every recipient permanently failed (bounced or was rejected).
  • rejected: Every recipient was rejected before a delivery attempt (for example, all recipients were suppressed).
  • partial_failure: Some recipients permanently failed while others were delivered or are still in flight.
  • canceled: A scheduled message was canceled before it was sent.

complained takes precedence over every other status: at least one recipient reported the message as spam, regardless of what happened to the rest.

accepted_countinteger required

How many recipients are in the accepted state, meaning we have the message and are getting ready to deliver it.

processed_countinteger required

How many recipients the message has been prepared for and queued for delivery.

delivered_countinteger required

How many recipients' messages were accepted by their mail server.

bounced_countinteger required

Number of recipients that resulted in a permanent delivery failure.

complained_countinteger required

Number of recipients that reported spam.

deferred_countinteger required

Number of recipients in transient delivery deferral. Their mail server asked for a retry, and delivery attempts continue.

rejected_countinteger required

Number of recipients rejected before delivery. Read the per-recipient rejection_reason field on GET /v1/email/messages/{message_id}/recipients for the specific cause.

processing_latency_msinteger nullable

Time between the send being accepted and the message being prepared for delivery, in milliseconds, for the fastest recipient. Null until the first recipient reaches processed.

delivery_latency_msinteger nullable

Time between the message being processed and the receiving mail server accepting it, in milliseconds, for the fastest delivered recipient. Null until the first recipient is delivered.

total_latency_msinteger nullable

End-to-end accept → delivered time for the fastest delivered recipient, in milliseconds. Null until the first recipient is delivered.

open_countinteger required

Total open events across all recipients.

click_countinteger required

Total click events across all recipients.

requested_languagestring

A language tag in BCP-47 form, for example en or pt-BR.

resolved_languagestring

A language tag in BCP-47 form, for example en or pt-BR.

template_idstring
template_version_idstring
broadcast_idstring
metadataobject

Any JSON you kept on the message. 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.

parametersobject nullable

The substitution values this send supplied, whether inline or from a template, or null if none were supplied. They are the values applied to subject and to the bodies the content endpoint returns, kept so you can see what produced the delivered copy and not only the result.

track_opensboolean required

Whether open tracking is enabled for this send.

track_clicksboolean required

Whether click tracking is enabled for this send.

created_atstring date-time required

When the send request was accepted.

thread_idstring nullable

Thread this message belongs to, or null when the message is not part of one.

in_reply_to_message_idstring
delivered_atstring date-time nullable

When all recipients reached a terminal delivered state, or null if not yet fully delivered.

scheduled_atstring date-time

When this message is scheduled to send, for a send created with a future send time. Absent for an immediate send. Stays set after the scheduled send fires.

Example response

{
  "id": "em_01krdgeqcxet5s7t44vh8rt9mg",
  "from": {
    "email": "onboarding@messagebird.dev",
    "name": "Bird"
  },
  "to": [
    {
      "email": "delivered@messagebird.dev"
    }
  ],
  "subject": "Hello from Bird",
  "category": "marketing",
  "status": "accepted",
  "broadcast_id": "eb_01krdgeqcxet5s7t44vh8rt9mg",
  "accepted_count": 1,
  "processed_count": 0,
  "delivered_count": 0,
  "bounced_count": 0,
  "complained_count": 0,
  "deferred_count": 0,
  "rejected_count": 0,
  "open_count": 0,
  "click_count": 0,
  "track_opens": false,
  "track_clicks": false,
  "created_at": "2026-07-01T12:00:00Z"
}

Changes

No recorded changes to this operation across all 2 revisions of this API.