---
title: "List events for a message"
method: GET
path: "/v1/email/messages/{message_id}/events"
tags: ["email-messages"]
---

# List events for a message

`GET /v1/email/messages/{message_id}/events`

## Request

- Base URL: `https://us1.platform.bird.com`
- URL: `https://us1.platform.bird.com/v1/email/messages/{message_id}/events`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `bird_session`

Returns the message's per-recipient event timeline, oldest first, as a cursor page. Lifecycle, failure, and engagement events interleave as they happen, and engagement events (`email.opened`, `email.clicked`) can repeat per recipient. Filter to one event type with `type`. For each recipient's current state rather than its history, use [List recipients of a message](/docs/api/reference/list-email-message-recipients).

## Path parameters

- `message_id` string, required

## Query parameters

- `limit` integer
- `starting_after` string
- `ending_before` string
- `type` string: Type of an event in a message's per-recipient delivery timeline. - `email.scheduled`: We accepted a send scheduled for a future time. Fires once for each message regardless of its recipient count. - `email.accepted`: We accepted the send and are getting ready to deliver it. Fires once per requested recipient. - `email.processed`: We queued the message for delivery to the recipient's mail server. - `email.deferred`: The recipient's mail server temporarily refused the message. Delivery remains pending and is retried. Can fire more than once per recipient. - `email.delivered`: The recipient's mail server accepted the message. - `email.bounced`: Delivery permanently failed at the recipient's mail server. - `email.out_of_band_bounce`: A bounce notification arrived after the message had already been accepted for delivery. - `email.rejected`: We rejected the message before attempting delivery, for example because the recipient is suppressed. - `email.canceled`: A scheduled send was canceled before it fired. Fires once for each message regardless of its recipient count. - `email.opened`: The recipient opened the message. Can fire more than once per recipient. - `email.clicked`: The recipient clicked a tracked link in the message. Can fire more than once per recipient. - `email.unsubscribed`: The recipient opted out through a tracked unsubscribe link in the message. - `email.list_unsubscribed`: The recipient opted out through the one-click unsubscribe control in their mail client. - `email.complained`: The recipient reported the message as spam through their mailbox provider. We can add new event types to this list over time, so treat a value you do not recognize as a new type rather than as an error.

## Headers

- `X-Workspace-Id` string
- `X-Organization-Id` string

## Response `200`

Paginated event timeline for this message.

- EmailEventList
  - `data` EmailEvent[], required: Page of timeline events for this email send, in chronological order.
    - `id` string, required: Event ID.
    - `type` string, required: Type of an event in a message's per-recipient delivery timeline. - `email.scheduled`: We accepted a send scheduled for a future time. Fires once for each message regardless of its recipient count. - `email.accepted`: We accepted the send and are getting ready to deliver it. Fires once per requested recipient. - `email.processed`: We queued the message for delivery to the recipient's mail server. - `email.deferred`: The recipient's mail server temporarily refused the message. Delivery remains pending and is retried. Can fire more than once per recipient. - `email.delivered`: The recipient's mail server accepted the message. - `email.bounced`: Delivery permanently failed at the recipient's mail server. - `email.out_of_band_bounce`: A bounce notification arrived after the message had already been accepted for delivery. - `email.rejected`: We rejected the message before attempting delivery, for example because the recipient is suppressed. - `email.canceled`: A scheduled send was canceled before it fired. Fires once for each message regardless of its recipient count. - `email.opened`: The recipient opened the message. Can fire more than once per recipient. - `email.clicked`: The recipient clicked a tracked link in the message. Can fire more than once per recipient. - `email.unsubscribed`: The recipient opted out through a tracked unsubscribe link in the message. - `email.list_unsubscribed`: The recipient opted out through the one-click unsubscribe control in their mail client. - `email.complained`: The recipient reported the message as spam through their mailbox provider. We can add new event types to this list over time, so treat a value you do not recognize as a new type rather than as an error.
    - `occurred_at` string, date-time, required: When this event occurred.
    - `recipient_id` string, required
    - `bounce_type` 'hard' | 'soft' | 'undetermined' | 'admin' | 'block' | 'null', nullable: Bounce classification. Present on `email.bounced`, `email.out_of_band_bounce`, and `email.deferred` events. - `hard`: a permanent failure (invalid address or non-existent domain). - `soft`: a transient failure (mailbox full or server temporarily unavailable). - `block`: the receiving mail server blocked the sending IP for reputation reasons. - `admin`: an administrative refusal (relaying denied or blocklisted domain). - `undetermined`: the receiving server's response is ambiguous.
    - `bounce_class` integer, nullable: A more detailed numeric bounce code, useful for telling apart failures that share the same `bounce_type`. For example, a DNS failure and a spam block can both come through as `bounce_type: soft` or `bounce_type: block`; this field tells you which one actually happened. Present on `email.bounced`, `email.out_of_band_bounce`, and `email.deferred` events.
    - `bounce_code` string, nullable: SMTP status code returned by the receiving mail server. Present on `email.bounced` and `email.deferred` events.
    - `bounce_description` string, nullable: The bounce reason, in plain language, as reported by the mail server. Present on `email.bounced` and `email.deferred` events.
    - `rejection_reason` 'recipient_suppressed' | 'transmission_failed' | 'generation_failure' | 'policy_rejection' | 'domain_unverified' | 'quota_exceeded' | 'recipient_not_allowed' | 'null', nullable: Specific cause of rejection. Present on `email.rejected` events only. - `recipient_suppressed`: The recipient is on the workspace suppression list. - `transmission_failed`: The message could not be transmitted for delivery. - `generation_failure`: The message could not be built for delivery, because of a template or content issue. - `policy_rejection`: The message was refused by sending policy. - `domain_unverified`: The sending domain was not verified. - `quota_exceeded`: The organization's send quota was reached. - `recipient_not_allowed`: This recipient was not allowed for this send. For a send from the shared onboarding domain, every recipient has to be a verified member of the workspace.
    - `sending_ip` string, nullable: The IP address used to send this message. Useful for spotting a deliverability problem that is tied to one specific sending IP rather than affecting all of them. Present on `email.delivered`, `email.bounced`, `email.out_of_band_bounce`, and `email.deferred` events.
    - `mailbox_provider` string, nullable: The recipient mailbox provider, as a lowercased classifier bucket (e.g. `gmail`, `yahoo`, `microsoft`, `apple`). Present on `email.processed`, `email.delivered`, `email.complained`, `email.bounced`, `email.out_of_band_bounce`, `email.deferred`, `email.rejected`, `email.unsubscribed`, `email.list_unsubscribed`, `email.opened`, and `email.clicked` events when the receiving mail system could be classified; null when it could not.
    - `mailbox_provider_region` string, nullable: The provider region, as reported by the receiving mail system (for example `NA`, `EU`, `APAC`). The set is open and provider-specific. Present on `email.processed`, `email.delivered`, `email.complained`, `email.bounced`, `email.out_of_band_bounce`, `email.deferred`, `email.rejected`, `email.unsubscribed`, `email.list_unsubscribed`, `email.opened`, and `email.clicked` events when reported; null otherwise.
    - `is_prefetched` boolean, nullable: True when the open was auto-fetched by an inbox privacy feature (Apple Mail Privacy Protection, the Gmail image proxy) rather than a person actually opening the message. Use it to calculate open rate accurately. Present on `email.opened` events only.
    - `url` string, nullable: The clicked URL. Present on `email.clicked` events, and on `email.unsubscribed` events when the recipient unsubscribed through a link in the message.
    - `link_name` string, nullable: The clicked link's own name, when the link in the message carried one, so a click can be reported by what the link said rather than where it pointed. Absent when the link had no name. Appears alongside `url` on `email.clicked` events, and on `email.unsubscribed` events when the recipient unsubscribed through a link.
    - `country` string, nullable: ISO 3166-1 alpha-2 country code derived from the client IP. Present on `email.opened` and `email.clicked` events when available.
    - `ip_address` string, nullable: Client IP address (IPv4 or IPv6). Present on `email.opened` and `email.clicked` events when available.
    - `user_agent` string, nullable: Client user-agent string. Present on `email.opened` and `email.clicked` events when available.
  - `next` NextAction[]: What to do next, given what this page reports. Present only where the read computes it: an empty list means the answer you were looking for is here and there is nothing further to do. Absent entirely on reads that do not report next actions.
    - `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.
    - `description` string, required: A short, human-readable label for the step, suitable for display.
    - `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.
    - `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.
    - `url` string, uri: 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.
  - `next_cursor` string, nullable, required: Cursor for the next page. Pass back as `starting_after` to advance forward. `null` when no next page exists.
  - `prev_cursor` string, nullable, required: Cursor for the previous page. Pass back as `ending_before` to step backward. `null` when no previous page exists.
  - `refresh_cursor` string, nullable, required: Refresh anchor, the first row of this response. Pass back as `ending_before` to fetch what precedes it in the current sort order. On a newest-first sort those are the items that have appeared since; on any other sort they are the items that sort earlier, so refreshing such a list means re-fetching it instead. Non-`null` whenever `data` is non-empty; `null` only on an empty page. Distinct from `prev_cursor`.

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Insufficient permissions
- `404`: Resource not found
- `422`: The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`.
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/messagebird/apis/bird-api.md) · [All operations](https://skmtc.dev/messagebird/apis/bird-api/llms.txt) · [OpenAPI document](https://skmtc.dev/messagebird/apis/bird-api/revisions/6dfce1179799?raw)
