events.md


title: "Events" description: "Read MachineMail's replayable event log for the organization, a pod or an inbox, or follow events live over Server-Sent Events or a WebSocket." canonical: "https://machinemail.dev/docs/reference/api/events"

Events

Read MachineMail's replayable event log for the organization, a pod or an inbox, or follow events live over Server-Sent Events or a WebSocket.

Source: https://machinemail.dev/docs/reference/api/events

Method Path Summary
GET /v0/events List Events
GET /v0/events/stream Stream Events (SSE)
GET /v0/events/{event_id} Get Event
GET /v0/inboxes/{inbox_id}/events List Events in Inbox
GET /v0/inboxes/{inbox_id}/events/{event_id} Get Event in Inbox
GET /v0/pods/{pod_id}/events List Events in Pod
GET /v0/pods/{pod_id}/events/{event_id} Get Event in Pod
GET /v0/ws WebSocket Event Stream

List Events

GET /v0/events

The replayable event log, newest first. Pass after (an event ID or a time) to read forward from a point, oldest first. Events are kept without a retention limit. Only the events the credential may read are listed, as on the live streams: message.* needs message_read, inbox.* inbox_read, domain.* domain_read, draft.* draft_read, webhook.test webhook_read, and the audit events (agent registrations, members) metrics_read. event_types cannot add others.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Query parameters

Field Type Description
limit integer Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_token string next_page_token from the previous page.
ascending boolean Sort oldest first. Defaults to true when after is set.
after string An event ID (evt_...): only events stored after it, in commit order. Or an ISO 8601 time: only events created after it. Either one makes the default order oldest first.
before string (date-time) Only events created before this time.
event_types ("message.received" | "message.received.spam" | "message.received.quarantined" | "message.received.unauthenticated" | "message.received.blocked" | "message.sent" | "message.delivered" | "message.bounced" | "message.complained" | "message.rejected" | "domain.verified" | "domain.updated" | "inbox.created" | "inbox.expired" | "draft.sent" | "webhook.test" | "trusted_domain.created" | "trusted_domain.updated" | "trusted_domain.deleted")[] Only these event types (repeat the parameter, or comma-separate). Omit for every type.
inbox_id string Only events of this inbox.
pod_id string Only events of this pod.

Response

200 A page of events (application/json)

Field Type Description
count integer required Number of items returned.
limit integer Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_token string Page token for pagination. Absent on the last page.
events Event[] required Newest first; oldest first when after is set or ascending is true.

Each item of events is a Event:

Field Type Description
event_id string required ID of the event (evt_...). Sorts by creation time.
event_type "message.received" | "message.received.spam" | "message.received.quarantined" | "message.received.unauthenticated" | "message.received.blocked" | "message.sent" | "message.delivered" | "message.bounced" | "message.complained" | "message.rejected" | "domain.verified" | "domain.updated" | "inbox.created" | "inbox.expired" | "draft.sent" | "webhook.test" | "trusted_domain.created" | "trusted_domain.updated" | "trusted_domain.deleted" | "registration.created" | "token.issued" | "agent.claimed" | "agent.revoked" | "member.invited" | "member.role_changed" | "member.removed" required Type of event.
organization_id string required ID of the organization.
pod_id string ID of the pod. Absent for organization-level events.
inbox_id string ID of the inbox. Absent for events without an inbox (for example domain.verified).
data Record<string, unknown> required Event payload.
timestamp string (date-time) required When the event happened.
created_at string (date-time) required When the event was stored.

Errors

Status Meaning
400 Invalid request: error.type is validation and error.param names the field.
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/events" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "events": [
    {
      "event_id": "evt_01k6x3g4pt0000k6t2wa8e1n3q",
      "event_type": "message.received",
      "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "inbox_id": "agent@machinemail.dev",
      "data": {
        "key": "value"
      },
      "timestamp": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z"
    }
  ]
}

Stream Events (SSE)

GET /v0/events/stream

Server-Sent Events of everything in the credential scope that its permissions allow, narrowed by the query filters.

Each event is sent only when the credential holds the read permission of what it describes: message.* needs message_read, domain.* needs domain_read, inbox.* needs inbox_read, draft.* needs draft_read, webhook.* needs webhook_read, trusted_domain.* needs trusted_domain_read. Other events are skipped, without an error, and event_types cannot add them. The credential is re-checked every 30 seconds: when it is revoked or expired, or its permissions or pod/inbox scope change, the stream ends with an error (reconnect to get the events the credential allows now).

Frames are id: <event_id>, event: <event_type>, data: <JSON>, where the JSON is the webhook event envelope. A stream opened with a dashboard session cookie also receives that person's session events. They go only to the session of the person they are about.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Query parameters

Field Type Description
inbox_id string[] Only events of these inboxes.
pod_id string[] Only events of these pods.
event_types ("message.received" | "message.received.spam" | "message.received.quarantined" | "message.received.unauthenticated" | "message.received.blocked" | "message.sent" | "message.delivered" | "message.bounced" | "message.complained" | "message.rejected" | "domain.verified" | "domain.updated" | "inbox.created" | "inbox.expired" | "draft.sent" | "webhook.test" | "trusted_domain.created" | "trusted_domain.updated" | "trusted_domain.deleted")[] Only these event types.

Headers

Field Type Description
Last-Event-Id string Resume after this event (evt_...): missed events are sent first.

Response

200 The event stream (text/event-stream)

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/events/stream" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
id: evt_01k6x3g4pt0000k6t2wa8e1n3q
data: {"event_id":"evt_01k6x3g4pt0000k6t2wa8e1n3q", ...}

Get Event

GET /v0/events/{event_id}

One event of the log. An event the credential may not read is a 404, like one outside its scope.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Path parameters

Field Type Description
event_id string required ID of the event (evt_...).

Response

200 The event (application/json)

Errors

Status Meaning
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request.
404 Not found. Also returned for resources outside the credential scope.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/events/evt_01k6x3g4pt0000k6t2wa8e1n3q" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
{
  "event_id": "evt_01k6x3g4pt0000k6t2wa8e1n3q",
  "event_type": "message.received",
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "inbox_id": "agent@machinemail.dev",
  "data": {
    "key": "value"
  },
  "timestamp": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z"
}

List Events in Inbox

GET /v0/inboxes/{inbox_id}/events

Same as List Events (GET /v0/events), limited to the inbox.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Path parameters

Field Type Description
inbox_id string required ID of the inbox.

Query parameters

Response

200 A page of events (application/json)

Each item of events is a Event:

Errors

Status Meaning
400 Invalid request: error.type is validation and error.param names the field.
401 Missing, invalid, expired or revoked credential.
403 The credential lacks the permission or scope for this request.
404 Not found. Also returned for resources outside the credential scope.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/events" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Get Event in Inbox

GET /v0/inboxes/{inbox_id}/events/{event_id}

Same as Get Event (GET /v0/events/{event_id}), limited to the inbox.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Path parameters

Field Type Description
inbox_id string required ID of the inbox.
event_id string required ID of the event (evt_...).

Response

200 The event (application/json)

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/inboxes/agent@machinemail.dev/events/evt_01k6x3g4pt0000k6t2wa8e1n3q" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

List Events in Pod

GET /v0/pods/{pod_id}/events

Same as List Events (GET /v0/events), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Path parameters

Field Type Description
pod_id string required ID of the pod.

Query parameters

Response

200 A page of events (application/json)

Each item of events is a Event:

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/events" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Get Event in Pod

GET /v0/pods/{pod_id}/events/{event_id}

Same as Get Event (GET /v0/events/{event_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read.

Path parameters

Field Type Description
pod_id string required ID of the pod.
event_id string required ID of the event (evt_...).

Response

200 The event (application/json)

Errors

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/events/evt_01k6x3g4pt0000k6t2wa8e1n3q" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

WebSocket Event Stream

GET /v0/ws

Upgrades to a WebSocket (send Connection: Upgrade and Upgrade: websocket). The socket starts subscribed to every event in the credential scope; query parameters are not read.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: metrics_read or message_read.

Response

101 Switching Protocols: the connection is now a WebSocket.

Errors

Status Meaning
400 The WebSocket handshake failed.
401 Missing, invalid, expired or revoked credential.
403 The credential holds no permission the stream serves events for.
404 Not found. Also returned for resources outside the credential scope.
500 Unexpected server error.

Error bodies use the error envelope.

Example

curl "https://api.machinemail.dev/v0/ws" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"