From c4545e251aa0549be64395321867bd9dcbc768f7 Mon Sep 17 00:00:00 2001 From: armandokun Date: Thu, 25 Jun 2026 17:34:11 +0300 Subject: [PATCH 1/3] docs(webhooks): document inbox/pod suspension + reactivation events Adds the reputation lifecycle webhook events (inbox.suspended, inbox.reactivated, pod.suspended, pod.reactivated) to the events reference: new entries in the events table, a dedicated reputation lifecycle payload example with field descriptions, and notes that these are HTTP-only and that the engine never auto-recovers a suspension. Updates the webhooks overview and page descriptions to mention lifecycle events alongside inbound email. Co-Authored-By: Claude Opus 4.8 --- concepts/webhooks.mdx | 2 +- pages/webhooks/events.mdx | 47 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/concepts/webhooks.mdx b/concepts/webhooks.mdx index 8dacc14..6469c90 100644 --- a/concepts/webhooks.mdx +++ b/concepts/webhooks.mdx @@ -4,7 +4,7 @@ description: "OpenMail webhooks deliver inbound email events to your endpoint in icon: eye --- -When an email arrives at one of your inboxes, OpenMail delivers it to your webhook URL as an HTTP POST request. +When an email arrives at one of your inboxes — or when the reputation engine suspends or reactivates an inbox or pod — OpenMail delivers the event to your webhook URL as an HTTP POST request. See [Events](/pages/webhooks/events) for the full list. ## Why use webhooks? diff --git a/pages/webhooks/events.mdx b/pages/webhooks/events.mdx index 6f78790..332381a 100644 --- a/pages/webhooks/events.mdx +++ b/pages/webhooks/events.mdx @@ -1,16 +1,22 @@ --- title: "Events" -description: "OpenMail webhook event reference — event types, full payload structure, and field descriptions for inbound email, thread updates, and delivery errors." +description: "OpenMail webhook event reference — event types, full payload structure, and field descriptions for inbound email and reputation lifecycle (inbox/pod suspension and reactivation) events." icon: bell --- -OpenMail sends webhooks when inbound email is received. Emails that are blocked by [sender rules](/concepts/sender-rules) or filtered out by allowlist mode do not trigger events. +OpenMail sends webhooks when inbound email is received, and when the reputation engine suspends or reactivates one of your inboxes or pods. Emails that are blocked by [sender rules](/concepts/sender-rules) or filtered out by allowlist mode do not trigger events. ## Events | Event | Description | |-------|-------------| | `message.received` | A new inbound email was delivered to an inbox | +| `inbox.suspended` | An inbox was suspended (sending blocked) by the reputation engine or an admin | +| `inbox.reactivated` | A previously suspended inbox was reactivated | +| `pod.suspended` | A pod was suspended — every inbox in it is blocked from sending | +| `pod.reactivated` | A previously suspended pod was reactivated | + +`inbox.*` and `pod.*` are **reputation lifecycle** events: they let you react when one of your end-users is cut off (for example, pause that agent) without your whole account being affected. We handle suspension automatically; these events tell you when it happens. They are delivered to your HTTP webhook only (not over [WebSockets](/concepts/websockets)). ## Use cases @@ -56,7 +62,7 @@ OpenMail sends webhooks when inbound email is received. Emails that are blocked | Field | Description | |-------|-------------| -| `event` | Event type; currently always `message.received` | +| `event` | Event type — e.g. `message.received` (see [Events](#events)) | | `event_id` | Unique ID for this delivery. Use for deduplication - we may retry. | | `occurred_at` | When the event happened. Use to sort if events arrive out of order. | | `inbox_id` | The inbox that received the message | @@ -67,6 +73,41 @@ OpenMail sends webhooks when inbound email is received. Emails that are blocked | `message.body_text` | Plain-text body | | `message.attachments` | Array of attachments with `url`, `parsedText` (extracted content), and `extractionMethod`. See [Attachments](/concepts/attachments). | +## Reputation lifecycle payload + +`inbox.suspended`, `inbox.reactivated`, `pod.suspended`, and `pod.reactivated` share the structure below. They carry a `reputation` object instead of a `message`. For `pod.*` events, `inbox_id` and `inbox_address` are `null`. + +```json +{ + "event": "inbox.suspended", + "event_id": "evt_def456", + "occurred_at": "2024-03-21T10:05:00.000Z", + "delivered_at": "2024-03-21T10:05:01.000Z", + "attempt": 1, + "inbox_id": "inb_92ma...", + "inbox_address": "agent@yourdomain.com", + "pod_id": "pod_abc...", + "reputation": { + "scope": "inbox", + "state": "suspended", + "reason": "bounce_rate_high", + "actor": "engine" + } +} +``` + +| Field | Description | +|-------|-------------| +| `inbox_id` | The affected inbox, or `null` for `pod.*` events | +| `inbox_address` | The affected inbox's email address, or `null` for `pod.*` events | +| `pod_id` | The affected pod (or the suspended inbox's pod), if any | +| `reputation.scope` | `inbox` or `pod` — what was suspended/reactivated | +| `reputation.state` | The new reputation state (e.g. `suspended`, `watch`) | +| `reputation.reason` | Why it was suspended (e.g. `bounce_rate_high`); `null` on reactivation | +| `reputation.actor` | What triggered it: `engine`, `phishing`, or `admin` | + +A suspended inbox or pod is blocked from sending until reactivated. The reputation engine never auto-recovers a suspension — reactivation is an explicit action, which is when the `*.reactivated` event fires. + ## Headers | Header | Description | From e0698c886821699bbe8e135c05ca38bdc1bda2ad Mon Sep 17 00:00:00 2001 From: armandokun Date: Thu, 25 Jun 2026 17:39:45 +0300 Subject: [PATCH 2/3] docs(webhooks): slim lifecycle payload to customer-safe reason codes Match the API: drop the internal reputation object (scope/state/actor) and raw reason strings; document a single top-level `reason` with a stable public code table (high_bounce_rate, high_complaint_rate, abuse, pod_degraded, manual_review, other). Co-Authored-By: Claude Opus 4.8 --- pages/webhooks/events.mdx | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pages/webhooks/events.mdx b/pages/webhooks/events.mdx index 332381a..63b1e88 100644 --- a/pages/webhooks/events.mdx +++ b/pages/webhooks/events.mdx @@ -75,7 +75,7 @@ OpenMail sends webhooks when inbound email is received, and when the reputation ## Reputation lifecycle payload -`inbox.suspended`, `inbox.reactivated`, `pod.suspended`, and `pod.reactivated` share the structure below. They carry a `reputation` object instead of a `message`. For `pod.*` events, `inbox_id` and `inbox_address` are `null`. +`inbox.suspended`, `inbox.reactivated`, `pod.suspended`, and `pod.reactivated` share the structure below. They carry a `reason` instead of a `message`. For `pod.*` events, `inbox_id` and `inbox_address` are `null`. ```json { @@ -87,12 +87,7 @@ OpenMail sends webhooks when inbound email is received, and when the reputation "inbox_id": "inb_92ma...", "inbox_address": "agent@yourdomain.com", "pod_id": "pod_abc...", - "reputation": { - "scope": "inbox", - "state": "suspended", - "reason": "bounce_rate_high", - "actor": "engine" - } + "reason": "high_bounce_rate" } ``` @@ -101,10 +96,18 @@ OpenMail sends webhooks when inbound email is received, and when the reputation | `inbox_id` | The affected inbox, or `null` for `pod.*` events | | `inbox_address` | The affected inbox's email address, or `null` for `pod.*` events | | `pod_id` | The affected pod (or the suspended inbox's pod), if any | -| `reputation.scope` | `inbox` or `pod` — what was suspended/reactivated | -| `reputation.state` | The new reputation state (e.g. `suspended`, `watch`) | -| `reputation.reason` | Why it was suspended (e.g. `bounce_rate_high`); `null` on reactivation | -| `reputation.actor` | What triggered it: `engine`, `phishing`, or `admin` | +| `reason` | Why it was suspended (see below); `null` on `*.reactivated` events | + +### Reason codes + +| Code | Meaning | +|------|---------| +| `high_bounce_rate` | Too many of the inbox's recipients bounced | +| `high_complaint_rate` | Too many recipients marked messages as spam | +| `abuse` | Phishing or abusive sending was detected | +| `pod_degraded` | The pod's overall sending health fell too far | +| `manual_review` | Suspended by OpenMail staff pending review | +| `other` | Suspended for another reason | A suspended inbox or pod is blocked from sending until reactivated. The reputation engine never auto-recovers a suspension — reactivation is an explicit action, which is when the `*.reactivated` event fires. From 7948aea07f7911184dc33a3a73b743d58bb17a8f Mon Sep 17 00:00:00 2001 From: armandokun Date: Thu, 25 Jun 2026 18:00:07 +0300 Subject: [PATCH 3/3] docs(webhooks): drop attempt/delivered_at from lifecycle payload example Match the API: these are delivery bookkeeping, not customer-facing fields. Receivers dedupe on event_id (X-Event-Id header). Co-Authored-By: Claude Opus 4.8 --- pages/webhooks/events.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/pages/webhooks/events.mdx b/pages/webhooks/events.mdx index 63b1e88..832bff3 100644 --- a/pages/webhooks/events.mdx +++ b/pages/webhooks/events.mdx @@ -82,8 +82,6 @@ OpenMail sends webhooks when inbound email is received, and when the reputation "event": "inbox.suspended", "event_id": "evt_def456", "occurred_at": "2024-03-21T10:05:00.000Z", - "delivered_at": "2024-03-21T10:05:01.000Z", - "attempt": 1, "inbox_id": "inb_92ma...", "inbox_address": "agent@yourdomain.com", "pod_id": "pod_abc...",