<Intro>

<EndpointHeader />

<Description>

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).

</Description>

</Intro>

<Parameters in="path">

<Parameter name="message_id" type="string">

<Description>

ID of the message whose timeline to read, from the send response's `id` field (`em_`-prefixed).

</Description>

</Parameter>

</Parameters>

<Parameters in="query">

<Parameter name="limit" type="integer">

<Description>

Maximum number of items to return per page.

</Description>

</Parameter>

<Parameter name="starting_after" type="string">

<Description>

Cursor from the `next_cursor` field of a previous list response. Returns items immediately after the cursor position in the current sort order.

</Description>

</Parameter>

<Parameter name="ending_before" type="string">

<Description>

Cursor from the `prev_cursor` field of a previous list response. Returns items immediately before the cursor position in the current sort order.

</Description>

</Parameter>

<Parameter name="type" type="string">

<Description>

Filter by event type (e.g. `email.bounced`, `email.opened`).

</Description>

</Parameter>

</Parameters>

<Payload kind="response">

<Field name="data" type="array of object" required>

<Description>

Page of timeline events for this email send, in chronological order.

</Description>

<FieldChildren kind="response">

<Field name="id" type="string" prefix="data." required>

<Description>

Event ID.

</Description>

</Field>

<Field name="type" type="string" prefix="data." required>

<Description>

Event type. `email.processed` means Bird has processed the message and queued it for delivery.

</Description>

<Description>

Possible values (may grow over time): `email.accepted`, `email.bounced`, `email.canceled`, `email.clicked`, `email.complained`, `email.deferred`, `email.delivered`, `email.list_unsubscribed`, `email.opened`, `email.out_of_band_bounce`, `email.processed`, `email.rejected`, `email.scheduled`, `email.unsubscribed`

</Description>

</Field>

<Field name="occurred_at" type="string" prefix="data." required>

<Description>

When this event occurred.

</Description>

</Field>

<Field name="recipient_id" type="string" prefix="data." required>

<Description>

Recipient this event applies to.

</Description>

</Field>

<Field name="bounce_type" type="nullable string" prefix="data.">

<Description>

Bounce classification. Present on `email.bounced`, `email.out_of_band_bounce`, and `email.deferred` events. `hard` is a permanent failure (invalid address or non-existent domain). `soft` is a transient failure (mailbox full, server temporarily unavailable). `block` indicates the receiving mail server blocked the sending IP for reputation reasons. `admin` indicates an administrative refusal (relaying denied, blocklisted domain). `undetermined` is used when the receiving server's response is ambiguous.

</Description>

<Description>

Possible values: `hard`, `soft`, `undetermined`, `admin`, `block`, `null`

</Description>

</Field>

<Field name="bounce_class" type="nullable integer" prefix="data.">

<Description>

Numeric bounce classification for fine-grained deliverability triage. Lets you distinguish, for example, a DNS failure from a spam block when both would be `bounce_type: soft` or `bounce_type: block`. Present on `email.bounced`, `email.out_of_band_bounce`, and `email.deferred`.

</Description>

</Field>

<Field name="bounce_code" type="nullable string" prefix="data.">

<Description>

SMTP status code returned by the receiving mail server. Present on `email.bounced` and `email.deferred` events.

</Description>

</Field>

<Field name="bounce_description" type="nullable string" prefix="data.">

<Description>

Human-readable bounce reason. Present on `email.bounced` and `email.deferred` events.

</Description>

</Field>

<Field name="rejection_reason" type="nullable string" prefix="data.">

<Description>

Specific cause of rejection. Present on `email.rejected` events only. See `EmailRecipient.rejection_reason` for the meaning of each value.

</Description>

<Description>

Possible values: `recipient_suppressed`, `transmission_failed`, `generation_failure`, `policy_rejection`, `domain_unverified`, `quota_exceeded`, `recipient_not_allowed`, `null`

</Description>

</Field>

<Field name="sending_ip" type="nullable string" prefix="data.">

<Description>

The IP address Bird used to send this message. Useful when investigating deliverability issues that correlate with specific IPs. Present on `email.delivered`, `email.bounced`, `email.out_of_band_bounce`, and `email.deferred` events.

</Description>

</Field>

<Field name="is_prefetched" type="nullable boolean" prefix="data.">

<Description>

True when the open was auto-fetched by an inbox privacy feature (Apple Mail Privacy Protection, Gmail image proxy) rather than a real user action. Useful for accurate open-rate calculation. Present on `email.opened` only.

</Description>

</Field>

<Field name="url" type="nullable string" prefix="data.">

<Description>

The clicked URL. Present on `email.clicked` events.

</Description>

</Field>

<Field name="country" type="nullable string" prefix="data.">

<Description>

ISO 3166-1 alpha-2 country code derived from the client IP. Present on `email.opened` and `email.clicked` events when available.

</Description>

</Field>

<Field name="ip_address" type="nullable string" prefix="data.">

<Description>

Client IP address (IPv4 or IPv6). Present on `email.opened` and `email.clicked` events when available.

</Description>

</Field>

<Field name="user_agent" type="nullable string" prefix="data.">

<Description>

Client user-agent string. Present on `email.opened` and `email.clicked` events when available.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="next_cursor" type="nullable string" required>

<Description>

Cursor for the next page. Pass back as `starting_after` to advance forward. Null when no next page exists.

</Description>

</Field>

<Field name="prev_cursor" type="nullable string" required>

<Description>

Cursor for the previous page. Pass back as `ending_before` to step backward. Null when no previous page exists.

</Description>

</Field>

<Field name="refresh_cursor" type="nullable string" required>

<Description>

Refresh anchor. Pass back as `ending_before` later to fetch items that have appeared since this response. Non-null whenever `data` is non-empty; null only on an empty page. Distinct from `prev_cursor`.

</Description>

</Field>

</Payload>