diff --git a/fern/apis/api/definition/events.yml b/fern/apis/api/definition/events.yml index a6ecb342..755cc83f 100644 --- a/fern/apis/api/definition/events.yml +++ b/fern/apis/api/definition/events.yml @@ -11,6 +11,8 @@ types: enum: - name: MESSAGE_RECEIVED value: message.received + - name: MESSAGE_RECEIVED_ENVELOPE + value: message.received.envelope - name: MESSAGE_RECEIVED_SPAM value: message.received.spam - name: MESSAGE_RECEIVED_BLOCKED @@ -37,6 +39,7 @@ types: docs: Event types for which to send events. MessageReceivedEventType: + docs: Full-content received variants only. The metadata-only envelope has a separate event schema. enum: - name: MESSAGE_RECEIVED value: message.received @@ -141,6 +144,53 @@ types: message_id: messages.MessageId timestamp: Timestamp + AuthenticationVerdict: + enum: + - pass + - fail + - none + - temperror + - permerror + - neutral + - softfail + + MessageAuthenticationResults: + docs: Optional producer-verified verdicts. Absence does not imply authentication passed; raw Authentication-Results headers are not trusted evidence. + properties: + spf: optional + dkim: optional + dmarc: optional + + ReceivedEnvelopeMessage: + docs: Selected metadata only. Labels and Message-ID remain user-controlled metadata; invalid addresses are omitted. No subject, body, preview, attachment or content URL is included. + properties: + organization_id: string + pod_id: string + inbox_id: inboxes.InboxId + thread_id: threads.ThreadId + message_id: messages.MessageId + timestamp: Timestamp + created_at: Timestamp + updated_at: Timestamp + from: optional + to: optional> + cc: optional> + bcc: optional> + reply_to: optional> + labels: list + authentication_results: optional + headers: + type: map + docs: Currently empty. No raw header values are allowlisted. + + MessageReceivedEnvelopeEvent: + docs: Opt-in pilot webhook, separate from the full-content received event. Requires support activation. Not emitted on WebSocket connections. + properties: + type: literal<"event"> + event_type: literal<"message.received.envelope"> + event_id: EventId + message: ReceivedEnvelopeMessage + MessageReceivedEvent: docs: A message was received. Spam, blocked, and unauthenticated received-message events use the same payload shape with different `event_type` values. properties: diff --git a/fern/apis/api/definition/webhooks/events.yml b/fern/apis/api/definition/webhooks/events.yml index 7d5c0c52..4d1678f7 100644 --- a/fern/apis/api/definition/webhooks/events.yml +++ b/fern/apis/api/definition/webhooks/events.yml @@ -17,6 +17,15 @@ types: docs: Signature of webhook message. webhooks: + messageReceivedEnvelope: + display-name: Message Received Envelope (Pilot) + method: POST + headers: + svix-id: SvixId + svix-signature: SvixSignature + svix-timestamp: SvixTimestamp + payload: events.MessageReceivedEnvelopeEvent + messageReceived: display-name: Message Received method: POST diff --git a/fern/pages/core-concepts/permissions.mdx b/fern/pages/core-concepts/permissions.mdx index 3c828a7d..6990cc65 100644 --- a/fern/pages/core-concepts/permissions.mdx +++ b/fern/pages/core-concepts/permissions.mdx @@ -102,6 +102,19 @@ Threads are groupings of messages and have no permissions of their own. Every th | `webhook_update` | Update webhooks | | `webhook_delete` | Delete webhooks | +For organizations enrolled in the support-controlled content-boundary pilot, an enabled +console content lock adds `message_read` checks when creating or retaining a body-bearing +received webhook. This includes channel and HTTP-header updates and idempotent returns +of existing subscriptions. Restricted-label requirements still apply. The +`message.received.envelope` webhook contains selected metadata and does not require +`message_read`. Organizations outside the enabled pilot retain their existing received +webhook permission behavior. Existing security-event requirements are unchanged. + +The lock applies to console JWTs, not independently issued API keys or internal proxy +credentials. Prior body subscriptions, content credentials and signed content URLs need +separate cleanup before activation. Locked pilot organizations use a signed REST client +and envelope webhooks; the console mail UI and WebSocket content stream are unavailable. + ### Domains | Permission | Description | diff --git a/fern/pages/webhooks/webhooks-events.mdx b/fern/pages/webhooks/webhooks-events.mdx index dbf9198e..9dc10c2f 100644 --- a/fern/pages/webhooks/webhooks-events.mdx +++ b/fern/pages/webhooks/webhooks-events.mdx @@ -18,6 +18,26 @@ All webhook payloads follow the same basic structure: } ``` +## Metadata-only received envelope (opt-in pilot) + +`message.received.envelope` is available only after support enables the content-boundary +pilot for your organization. It has its own `MessageReceivedEnvelopeEvent` schema; +do not parse it as `MessageReceivedEvent`, which requires a full message and thread. +It includes IDs, timestamps, bare addresses, labels, optional verified authentication +results and an empty `headers` object. It excludes subject, body, preview, attachments, +content URLs and the thread object. Malformed address values are omitted. Labels and +Message-ID remain user-controlled strings; selected metadata is not a general trust signal. + +Authentication results can be absent on both new and legacy rows until the separate +verification producer is deployed. Absence must never be interpreted as a passing verdict. +Raw Authentication-Results headers are not forwarded as trusted results. + +The event has a stable ID distinct from the corresponding full-content event. Handle +redelivery and deduplicate by `svix-id`; ordering is not guaranteed. This pilot does not +add envelope events to WebSockets. Schema definitions do not imply that an already +installed SDK release supports the new event; handle raw JSON until using a compatible +release. Ordinary full-content event examples below are unchanged. + ## Parsing events with SDKs The AgentMail SDKs export typed classes for each webhook payload shape, so you can parse raw payloads into fully typed objects.