From d85aa4fb6ba5dcd8e9227c790c3fb30955588115 Mon Sep 17 00:00:00 2001 From: dielduarte Date: Thu, 17 Sep 2026 16:34:15 -0300 Subject: [PATCH 1/2] feat(webhooks): add support for suppression.added/removed events WebhookEvent and WebhookEventPayload had no members for suppression events, unlike the Node SDK. Adds SuppressionEventData and the SuppressionAddedEvent/SuppressionRemovedEvent payload types, reusing the existing SuppressionOrigin type. Co-Authored-By: Claude Sonnet 5 --- resend/__init__.py | 6 ++++ resend/version.py | 2 +- resend/webhooks/_webhook.py | 3 ++ resend/webhooks/_webhook_event.py | 48 +++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/resend/__init__.py b/resend/__init__.py index 912067e..0a9e082 100644 --- a/resend/__init__.py +++ b/resend/__init__.py @@ -85,6 +85,9 @@ EmailReceivedEvent, EmailScheduledEvent, EmailSentEvent, EmailSuppressedEvent, ReceivedEmailEventData, + SuppressionAddedEvent, + SuppressionEventData, + SuppressionRemovedEvent, WebhookEventPayload) from .webhooks._webhooks import Webhooks @@ -205,6 +208,9 @@ "DomainCreatedEvent", "DomainUpdatedEvent", "DomainDeletedEvent", + "SuppressionEventData", + "SuppressionAddedEvent", + "SuppressionRemovedEvent", "Topic", "OAuthGrant", "OAuthGrantClient", diff --git a/resend/version.py b/resend/version.py index f03beee..affdb22 100644 --- a/resend/version.py +++ b/resend/version.py @@ -1,4 +1,4 @@ -__version__ = "2.46.0" +__version__ = "2.47.0" def get_version() -> str: diff --git a/resend/webhooks/_webhook.py b/resend/webhooks/_webhook.py index caf0aa5..0f82eac 100644 --- a/resend/webhooks/_webhook.py +++ b/resend/webhooks/_webhook.py @@ -25,6 +25,9 @@ "domain.created", "domain.updated", "domain.deleted", + # Suppression events + "suppression.added", + "suppression.removed", ] diff --git a/resend/webhooks/_webhook_event.py b/resend/webhooks/_webhook_event.py index 34c8b1b..4fc85e6 100644 --- a/resend/webhooks/_webhook_event.py +++ b/resend/webhooks/_webhook_event.py @@ -2,6 +2,8 @@ from typing_extensions import Literal, NotRequired, TypedDict +from resend.suppressions._suppression import SuppressionOrigin + # Functional syntax required because ``from`` is a reserved keyword. _FromField = TypedDict( "_FromField", @@ -353,6 +355,34 @@ class DomainEventData(TypedDict): """ +class SuppressionEventData(TypedDict): + """ + ``data`` payload for suppression webhook events. + """ + + id: str + """ + The suppression ID. + """ + email: str + """ + The suppressed email address. + """ + origin: SuppressionOrigin + """ + What caused the address to be suppressed. + """ + source_id: Optional[str] + """ + The ID of the event that caused the suppression, such as the email that + bounced or complained. None for manual suppressions. + """ + created_at: str + """ + When the suppression was created. + """ + + class EmailSentEvent(TypedDict): """Webhook payload for ``email.sent``.""" @@ -489,6 +519,22 @@ class DomainDeletedEvent(TypedDict): data: DomainEventData +class SuppressionAddedEvent(TypedDict): + """Webhook payload for ``suppression.added``.""" + + type: Literal["suppression.added"] + created_at: str + data: SuppressionEventData + + +class SuppressionRemovedEvent(TypedDict): + """Webhook payload for ``suppression.removed``.""" + + type: Literal["suppression.removed"] + created_at: str + data: SuppressionEventData + + WebhookEventPayload = Union[ EmailSentEvent, EmailScheduledEvent, @@ -507,6 +553,8 @@ class DomainDeletedEvent(TypedDict): DomainCreatedEvent, DomainUpdatedEvent, DomainDeletedEvent, + SuppressionAddedEvent, + SuppressionRemovedEvent, ] """ Union of all Resend webhook event payload shapes returned by ``Webhooks.verify``. From f98d60cb58650ed99815f2056a2d8d5218ef9086 Mon Sep 17 00:00:00 2001 From: dielduarte Date: Thu, 17 Sep 2026 17:12:42 -0300 Subject: [PATCH 2/2] refactor(webhooks): reuse SuppressionListItem for the event payload SuppressionEventData duplicated SuppressionListItem's fields exactly, risking drift between the webhook and REST API contracts. Inherit instead of redeclaring. Co-Authored-By: Claude Sonnet 5 --- resend/webhooks/_webhook_event.py | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/resend/webhooks/_webhook_event.py b/resend/webhooks/_webhook_event.py index 4fc85e6..65c4902 100644 --- a/resend/webhooks/_webhook_event.py +++ b/resend/webhooks/_webhook_event.py @@ -2,7 +2,7 @@ from typing_extensions import Literal, NotRequired, TypedDict -from resend.suppressions._suppression import SuppressionOrigin +from resend.suppressions._suppression import SuppressionListItem # Functional syntax required because ``from`` is a reserved keyword. _FromField = TypedDict( @@ -355,31 +355,12 @@ class DomainEventData(TypedDict): """ -class SuppressionEventData(TypedDict): +class SuppressionEventData(SuppressionListItem): """ ``data`` payload for suppression webhook events. - """ - id: str - """ - The suppression ID. - """ - email: str - """ - The suppressed email address. - """ - origin: SuppressionOrigin - """ - What caused the address to be suppressed. - """ - source_id: Optional[str] - """ - The ID of the event that caused the suppression, such as the email that - bounced or complained. None for manual suppressions. - """ - created_at: str - """ - When the suppression was created. + Same shape as ``SuppressionListItem``: ``id``, ``email``, ``origin``, + ``source_id``, ``created_at``. """