From faf60f27ad7a25c3f426ca88a01e6df20a473bcd Mon Sep 17 00:00:00 2001 From: David Blackman Date: Thu, 12 Feb 2026 09:29:08 +0300 Subject: [PATCH 1/4] Add 21 missing event and webhook types from WorkOS docs Add support for the following event types that were documented but missing from the SDK: - api_key.created, api_key.revoked - authentication.email_verification_failed, authentication.mfa_failed, authentication.passkey_failed, authentication.passkey_succeeded, authentication.radar_risk_detected - connection.saml_certificate_renewed, connection.saml_certificate_renewal_required - flag.created, flag.updated, flag.deleted, flag.rule_updated - invitation.resent - organization_role.created, organization_role.deleted, organization_role.updated - permission.created, permission.deleted, permission.updated New payload models: ApiKeyPayload, ConnectionSamlCertificate payloads, FlagPayload, OrganizationRolePayload, PermissionPayload. New auth payloads for email_verification_failed, mfa_failed, passkey, and radar_risk_detected. Co-Authored-By: Claude Opus 4.6 --- src/workos/types/events/__init__.py | 5 + src/workos/types/events/api_key_payload.py | 19 +++ .../types/events/authentication_payload.py | 25 ++++ .../connection_saml_certificate_payload.py | 30 +++++ src/workos/types/events/event.py | 123 +++++++++++++++++ src/workos/types/events/event_model.py | 24 ++++ src/workos/types/events/event_type.py | 20 +++ src/workos/types/events/flag_payload.py | 14 ++ .../types/events/organization_role_payload.py | 14 ++ src/workos/types/events/permission_payload.py | 13 ++ src/workos/types/webhooks/webhook.py | 125 ++++++++++++++++++ 11 files changed, 412 insertions(+) create mode 100644 src/workos/types/events/api_key_payload.py create mode 100644 src/workos/types/events/connection_saml_certificate_payload.py create mode 100644 src/workos/types/events/flag_payload.py create mode 100644 src/workos/types/events/organization_role_payload.py create mode 100644 src/workos/types/events/permission_payload.py diff --git a/src/workos/types/events/__init__.py b/src/workos/types/events/__init__.py index ba6f15ba..848c5455 100644 --- a/src/workos/types/events/__init__.py +++ b/src/workos/types/events/__init__.py @@ -1,5 +1,7 @@ +from .api_key_payload import * from .authentication_payload import * from .connection_payload_with_legacy_fields import * +from .connection_saml_certificate_payload import * from .directory_group_membership_payload import * from .directory_group_with_previous_attributes import * from .directory_payload import * @@ -8,6 +10,9 @@ from .event_model import * from .event_type import * from .event import * +from .flag_payload import * from .organization_domain_verification_failed_payload import * +from .organization_role_payload import * +from .permission_payload import * from .previous_attributes import * from .session_payload import * diff --git a/src/workos/types/events/api_key_payload.py b/src/workos/types/events/api_key_payload.py new file mode 100644 index 00000000..83e10e8a --- /dev/null +++ b/src/workos/types/events/api_key_payload.py @@ -0,0 +1,19 @@ +from typing import Literal, Optional, Sequence +from workos.types.workos_model import WorkOSModel + + +class ApiKeyOwner(WorkOSModel): + id: str + type: str + + +class ApiKeyPayload(WorkOSModel): + object: Literal["api_key"] + id: str + name: str + owner: ApiKeyOwner + obfuscated_value: str + permissions: Sequence[str] + last_used_at: Optional[str] = None + created_at: str + updated_at: str diff --git a/src/workos/types/events/authentication_payload.py b/src/workos/types/events/authentication_payload.py index e013a1f5..56adcebd 100644 --- a/src/workos/types/events/authentication_payload.py +++ b/src/workos/types/events/authentication_payload.py @@ -29,6 +29,10 @@ class AuthenticationEmailVerificationSucceededPayload(AuthenticationResultSuccee user_id: str +class AuthenticationEmailVerificationFailedPayload(AuthenticationResultFailed): + type: Literal["email_verification"] + + class AuthenticationMagicAuthFailedPayload(AuthenticationResultFailed): type: Literal["magic_auth"] @@ -43,6 +47,10 @@ class AuthenticationMfaSucceededPayload(AuthenticationResultSucceeded): user_id: Optional[str] = None +class AuthenticationMfaFailedPayload(AuthenticationResultFailed): + type: Literal["mfa"] + + class AuthenticationOauthFailedPayload(AuthenticationResultFailed): type: Literal["oauth"] @@ -52,6 +60,15 @@ class AuthenticationOauthSucceededPayload(AuthenticationResultSucceeded): user_id: Optional[str] = None +class AuthenticationPasskeyFailedPayload(AuthenticationResultFailed): + type: Literal["passkey"] + + +class AuthenticationPasskeySucceededPayload(AuthenticationResultSucceeded): + type: Literal["passkey"] + user_id: str + + class AuthenticationPasswordFailedPayload(AuthenticationResultFailed): type: Literal["password"] @@ -76,3 +93,11 @@ class AuthenticationSsoSucceededPayload(AuthenticationResultSucceeded): type: Literal["sso"] user_id: Optional[str] = None sso: Optional[AuthenticationSsoData] = None + + +class AuthenticationRadarRiskDetectedPayload(AuthenticationResultCommon): + auth_method: str + action: str + control: str + blocklist_type: Optional[str] = None + user_id: Optional[str] = None diff --git a/src/workos/types/events/connection_saml_certificate_payload.py b/src/workos/types/events/connection_saml_certificate_payload.py new file mode 100644 index 00000000..badfd042 --- /dev/null +++ b/src/workos/types/events/connection_saml_certificate_payload.py @@ -0,0 +1,30 @@ +from typing import Literal +from workos.types.workos_model import WorkOSModel + +SamlCertificateType = Literal["ResponseSigning", "RequestSigning", "ResponseEncryption"] + + +class SamlCertificateConnection(WorkOSModel): + id: str + organization_id: str + + +class SamlCertificate(WorkOSModel): + certificate_type: SamlCertificateType + expiry_date: str + + +class SamlCertificateWithExpiry(SamlCertificate): + is_expired: bool + + +class ConnectionSamlCertificateRenewedPayload(WorkOSModel): + connection: SamlCertificateConnection + certificate: SamlCertificate + renewed_at: str + + +class ConnectionSamlCertificateRenewalRequiredPayload(WorkOSModel): + connection: SamlCertificateConnection + certificate: SamlCertificateWithExpiry + days_until_expiry: int diff --git a/src/workos/types/events/event.py b/src/workos/types/events/event.py index 01cf9771..107d24c7 100644 --- a/src/workos/types/events/event.py +++ b/src/workos/types/events/event.py @@ -4,21 +4,31 @@ from workos.types.user_management import OrganizationMembership, User from workos.types.directory_sync.directory_group import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser +from workos.types.events.api_key_payload import ApiKeyPayload from workos.types.events.authentication_payload import ( + AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, AuthenticationMagicAuthFailedPayload, AuthenticationMagicAuthSucceededPayload, + AuthenticationMfaFailedPayload, AuthenticationMfaSucceededPayload, AuthenticationOauthFailedPayload, AuthenticationOauthSucceededPayload, + AuthenticationPasskeyFailedPayload, + AuthenticationPasskeySucceededPayload, AuthenticationPasswordFailedPayload, AuthenticationPasswordSucceededPayload, + AuthenticationRadarRiskDetectedPayload, AuthenticationSsoFailedPayload, AuthenticationSsoSucceededPayload, ) from workos.types.events.connection_payload_with_legacy_fields import ( ConnectionPayloadWithLegacyFields, ) +from workos.types.events.connection_saml_certificate_payload import ( + ConnectionSamlCertificateRenewedPayload, + ConnectionSamlCertificateRenewalRequiredPayload, +) from workos.types.events.directory_group_membership_payload import ( DirectoryGroupMembershipPayload, ) @@ -33,9 +43,12 @@ DirectoryUserWithPreviousAttributes, ) from workos.types.events.event_model import EventModel +from workos.types.events.flag_payload import FlagPayload from workos.types.events.organization_domain_verification_failed_payload import ( OrganizationDomainVerificationFailedPayload, ) +from workos.types.events.organization_role_payload import OrganizationRolePayload +from workos.types.events.permission_payload import PermissionPayload from workos.types.events.session_payload import ( SessionCreatedPayload, SessionRevokedPayload, @@ -58,6 +71,20 @@ # the event name is added to the EventType union type in event_type.py. +class ApiKeyCreatedEvent(EventModel[ApiKeyPayload]): + event: Literal["api_key.created"] + + +class ApiKeyRevokedEvent(EventModel[ApiKeyPayload]): + event: Literal["api_key.revoked"] + + +class AuthenticationEmailVerificationFailedEvent( + EventModel[AuthenticationEmailVerificationFailedPayload,] +): + event: Literal["authentication.email_verification_failed"] + + class AuthenticationEmailVerificationSucceededEvent( EventModel[AuthenticationEmailVerificationSucceededPayload,] ): @@ -76,6 +103,10 @@ class AuthenticationMagicAuthSucceededEvent( event: Literal["authentication.magic_auth_succeeded"] +class AuthenticationMfaFailedEvent(EventModel[AuthenticationMfaFailedPayload]): + event: Literal["authentication.mfa_failed"] + + class AuthenticationMfaSucceededEvent(EventModel[AuthenticationMfaSucceededPayload]): event: Literal["authentication.mfa_succeeded"] @@ -90,6 +121,16 @@ class AuthenticationOauthSucceededEvent( event: Literal["authentication.oauth_succeeded"] +class AuthenticationPasskeyFailedEvent(EventModel[AuthenticationPasskeyFailedPayload]): + event: Literal["authentication.passkey_failed"] + + +class AuthenticationPasskeySucceededEvent( + EventModel[AuthenticationPasskeySucceededPayload] +): + event: Literal["authentication.passkey_succeeded"] + + class AuthenticationPasswordFailedEvent( EventModel[AuthenticationPasswordFailedPayload] ): @@ -102,6 +143,12 @@ class AuthenticationPasswordSucceededEvent( event: Literal["authentication.password_succeeded"] +class AuthenticationRadarRiskDetectedEvent( + EventModel[AuthenticationRadarRiskDetectedPayload] +): + event: Literal["authentication.radar_risk_detected"] + + class AuthenticationSsoFailedEvent(EventModel[AuthenticationSsoFailedPayload]): event: Literal["authentication.sso_failed"] @@ -122,6 +169,18 @@ class ConnectionDeletedEvent(EventModel[Connection]): event: Literal["connection.deleted"] +class ConnectionSamlCertificateRenewedEvent( + EventModel[ConnectionSamlCertificateRenewedPayload] +): + event: Literal["connection.saml_certificate_renewed"] + + +class ConnectionSamlCertificateRenewalRequiredEvent( + EventModel[ConnectionSamlCertificateRenewalRequiredPayload] +): + event: Literal["connection.saml_certificate_renewal_required"] + + class DirectoryActivatedEvent(EventModel[DirectoryPayloadWithLegacyFieldsForEventsApi]): event: Literal["dsync.activated"] @@ -166,6 +225,22 @@ class EmailVerificationCreatedEvent(EventModel[EmailVerificationCommon]): event: Literal["email_verification.created"] +class FlagCreatedEvent(EventModel[FlagPayload]): + event: Literal["flag.created"] + + +class FlagDeletedEvent(EventModel[FlagPayload]): + event: Literal["flag.deleted"] + + +class FlagRuleUpdatedEvent(EventModel[FlagPayload]): + event: Literal["flag.rule_updated"] + + +class FlagUpdatedEvent(EventModel[FlagPayload]): + event: Literal["flag.updated"] + + class InvitationAcceptedEvent(EventModel[InvitationCommon]): event: Literal["invitation.accepted"] @@ -174,6 +249,10 @@ class InvitationCreatedEvent(EventModel[InvitationCommon]): event: Literal["invitation.created"] +class InvitationResentEvent(EventModel[InvitationCommon]): + event: Literal["invitation.resent"] + + class InvitationRevokedEvent(EventModel[InvitationCommon]): event: Literal["invitation.revoked"] @@ -228,6 +307,18 @@ class OrganizationMembershipUpdatedEvent(EventModel[OrganizationMembership]): event: Literal["organization_membership.updated"] +class OrganizationRoleCreatedEvent(EventModel[OrganizationRolePayload]): + event: Literal["organization_role.created"] + + +class OrganizationRoleDeletedEvent(EventModel[OrganizationRolePayload]): + event: Literal["organization_role.deleted"] + + +class OrganizationRoleUpdatedEvent(EventModel[OrganizationRolePayload]): + event: Literal["organization_role.updated"] + + class PasswordResetCreatedEvent(EventModel[PasswordResetCommon]): event: Literal["password_reset.created"] @@ -236,6 +327,18 @@ class PasswordResetSucceededEvent(EventModel[PasswordResetCommon]): event: Literal["password_reset.succeeded"] +class PermissionCreatedEvent(EventModel[PermissionPayload]): + event: Literal["permission.created"] + + +class PermissionDeletedEvent(EventModel[PermissionPayload]): + event: Literal["permission.deleted"] + + +class PermissionUpdatedEvent(EventModel[PermissionPayload]): + event: Literal["permission.updated"] + + class RoleCreatedEvent(EventModel[EventRole]): event: Literal["role.created"] @@ -270,19 +373,28 @@ class UserUpdatedEvent(EventModel[User]): Event = Annotated[ Union[ + ApiKeyCreatedEvent, + ApiKeyRevokedEvent, + AuthenticationEmailVerificationFailedEvent, AuthenticationEmailVerificationSucceededEvent, AuthenticationMagicAuthFailedEvent, AuthenticationMagicAuthSucceededEvent, + AuthenticationMfaFailedEvent, AuthenticationMfaSucceededEvent, AuthenticationOauthFailedEvent, AuthenticationOauthSucceededEvent, + AuthenticationPasskeyFailedEvent, + AuthenticationPasskeySucceededEvent, AuthenticationPasswordFailedEvent, AuthenticationPasswordSucceededEvent, + AuthenticationRadarRiskDetectedEvent, AuthenticationSsoFailedEvent, AuthenticationSsoSucceededEvent, ConnectionActivatedEvent, ConnectionDeactivatedEvent, ConnectionDeletedEvent, + ConnectionSamlCertificateRenewedEvent, + ConnectionSamlCertificateRenewalRequiredEvent, DirectoryActivatedEvent, DirectoryDeletedEvent, DirectoryGroupCreatedEvent, @@ -294,8 +406,13 @@ class UserUpdatedEvent(EventModel[User]): DirectoryUserAddedToGroupEvent, DirectoryUserRemovedFromGroupEvent, EmailVerificationCreatedEvent, + FlagCreatedEvent, + FlagDeletedEvent, + FlagRuleUpdatedEvent, + FlagUpdatedEvent, InvitationAcceptedEvent, InvitationCreatedEvent, + InvitationResentEvent, InvitationRevokedEvent, MagicAuthCreatedEvent, OrganizationCreatedEvent, @@ -309,8 +426,14 @@ class UserUpdatedEvent(EventModel[User]): OrganizationMembershipCreatedEvent, OrganizationMembershipDeletedEvent, OrganizationMembershipUpdatedEvent, + OrganizationRoleCreatedEvent, + OrganizationRoleDeletedEvent, + OrganizationRoleUpdatedEvent, PasswordResetCreatedEvent, PasswordResetSucceededEvent, + PermissionCreatedEvent, + PermissionDeletedEvent, + PermissionUpdatedEvent, RoleCreatedEvent, RoleDeletedEvent, RoleUpdatedEvent, diff --git a/src/workos/types/events/event_model.py b/src/workos/types/events/event_model.py index d89a7054..a20a5ab1 100644 --- a/src/workos/types/events/event_model.py +++ b/src/workos/types/events/event_model.py @@ -3,21 +3,31 @@ from workos.types.workos_model import WorkOSModel from workos.types.directory_sync.directory_group import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser +from workos.types.events.api_key_payload import ApiKeyPayload from workos.types.events.authentication_payload import ( + AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, AuthenticationMagicAuthFailedPayload, AuthenticationMagicAuthSucceededPayload, + AuthenticationMfaFailedPayload, AuthenticationMfaSucceededPayload, AuthenticationOauthFailedPayload, AuthenticationOauthSucceededPayload, + AuthenticationPasskeyFailedPayload, + AuthenticationPasskeySucceededPayload, AuthenticationPasswordFailedPayload, AuthenticationPasswordSucceededPayload, + AuthenticationRadarRiskDetectedPayload, AuthenticationSsoFailedPayload, AuthenticationSsoSucceededPayload, ) from workos.types.events.connection_payload_with_legacy_fields import ( ConnectionPayloadWithLegacyFields, ) +from workos.types.events.connection_saml_certificate_payload import ( + ConnectionSamlCertificateRenewedPayload, + ConnectionSamlCertificateRenewalRequiredPayload, +) from workos.types.events.directory_group_membership_payload import ( DirectoryGroupMembershipPayload, ) @@ -32,9 +42,12 @@ from workos.types.events.directory_user_with_previous_attributes import ( DirectoryUserWithPreviousAttributes, ) +from workos.types.events.flag_payload import FlagPayload from workos.types.events.organization_domain_verification_failed_payload import ( OrganizationDomainVerificationFailedPayload, ) +from workos.types.events.organization_role_payload import OrganizationRolePayload +from workos.types.events.permission_payload import PermissionPayload from workos.types.events.session_payload import ( SessionCreatedPayload, @@ -54,18 +67,26 @@ EventPayload = TypeVar( "EventPayload", + ApiKeyPayload, + AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, AuthenticationMagicAuthFailedPayload, AuthenticationMagicAuthSucceededPayload, + AuthenticationMfaFailedPayload, AuthenticationMfaSucceededPayload, AuthenticationOauthFailedPayload, AuthenticationOauthSucceededPayload, + AuthenticationPasskeyFailedPayload, + AuthenticationPasskeySucceededPayload, AuthenticationPasswordFailedPayload, AuthenticationPasswordSucceededPayload, + AuthenticationRadarRiskDetectedPayload, AuthenticationSsoFailedPayload, AuthenticationSsoSucceededPayload, Connection, ConnectionPayloadWithLegacyFields, + ConnectionSamlCertificateRenewedPayload, + ConnectionSamlCertificateRenewalRequiredPayload, DirectoryPayload, DirectoryPayloadWithLegacyFields, # TODO: Remove once merged with DirectoryPayloadWithLegacyFields in next major release. @@ -77,13 +98,16 @@ DirectoryGroupMembershipPayload, EmailVerificationCommon, EventRole, + FlagPayload, InvitationCommon, MagicAuthCommon, OrganizationCommon, OrganizationDomain, OrganizationDomainVerificationFailedPayload, OrganizationMembership, + OrganizationRolePayload, PasswordResetCommon, + PermissionPayload, SessionCreatedPayload, SessionRevokedPayload, User, diff --git a/src/workos/types/events/event_type.py b/src/workos/types/events/event_type.py index fb4027a8..ca6f9447 100644 --- a/src/workos/types/events/event_type.py +++ b/src/workos/types/events/event_type.py @@ -5,19 +5,28 @@ # and added to the Event class union type in event.py. EventType = Literal[ + "api_key.created", + "api_key.revoked", + "authentication.email_verification_failed", "authentication.email_verification_succeeded", "authentication.magic_auth_failed", "authentication.magic_auth_succeeded", + "authentication.mfa_failed", "authentication.mfa_succeeded", "authentication.oauth_failed", "authentication.oauth_succeeded", + "authentication.passkey_failed", + "authentication.passkey_succeeded", "authentication.password_failed", "authentication.password_succeeded", + "authentication.radar_risk_detected", "authentication.sso_failed", "authentication.sso_succeeded", "connection.activated", "connection.deactivated", "connection.deleted", + "connection.saml_certificate_renewed", + "connection.saml_certificate_renewal_required", "dsync.activated", "dsync.deleted", "dsync.group.created", @@ -29,8 +38,13 @@ "dsync.group.user_added", "dsync.group.user_removed", "email_verification.created", + "flag.created", + "flag.deleted", + "flag.rule_updated", + "flag.updated", "invitation.accepted", "invitation.created", + "invitation.resent", "invitation.revoked", "magic_auth.created", "organization.created", @@ -44,8 +58,14 @@ "organization_membership.created", "organization_membership.deleted", "organization_membership.updated", + "organization_role.created", + "organization_role.deleted", + "organization_role.updated", "password_reset.created", "password_reset.succeeded", + "permission.created", + "permission.deleted", + "permission.updated", "role.created", "role.deleted", "role.updated", diff --git a/src/workos/types/events/flag_payload.py b/src/workos/types/events/flag_payload.py new file mode 100644 index 00000000..c933379b --- /dev/null +++ b/src/workos/types/events/flag_payload.py @@ -0,0 +1,14 @@ +from typing import Literal, Optional, Sequence + +from workos.types.workos_model import WorkOSModel + + +class FlagPayload(WorkOSModel): + object: Literal["flag"] + id: str + name: str + slug: str + description: Optional[str] = None + tags: Optional[Sequence[str]] = None + created_at: str + updated_at: str diff --git a/src/workos/types/events/organization_role_payload.py b/src/workos/types/events/organization_role_payload.py new file mode 100644 index 00000000..162c3fe1 --- /dev/null +++ b/src/workos/types/events/organization_role_payload.py @@ -0,0 +1,14 @@ +from typing import Literal, Optional, Sequence +from workos.types.workos_model import WorkOSModel + + +class OrganizationRolePayload(WorkOSModel): + object: Literal["organization_role"] + organization_id: str + slug: str + name: str + description: Optional[str] = None + resource_type_slug: Optional[str] = None + permissions: Sequence[str] + created_at: str + updated_at: str diff --git a/src/workos/types/events/permission_payload.py b/src/workos/types/events/permission_payload.py new file mode 100644 index 00000000..514af392 --- /dev/null +++ b/src/workos/types/events/permission_payload.py @@ -0,0 +1,13 @@ +from typing import Literal, Optional +from workos.types.workos_model import WorkOSModel + + +class PermissionPayload(WorkOSModel): + object: Literal["permission"] + id: str + slug: str + name: str + description: Optional[str] = None + system: bool + created_at: str + updated_at: str diff --git a/src/workos/types/webhooks/webhook.py b/src/workos/types/webhooks/webhook.py index bca584bd..e218bed8 100644 --- a/src/workos/types/webhooks/webhook.py +++ b/src/workos/types/webhooks/webhook.py @@ -5,21 +5,31 @@ from workos.types.directory_sync import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser +from workos.types.events.api_key_payload import ApiKeyPayload from workos.types.events.authentication_payload import ( + AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, AuthenticationMagicAuthFailedPayload, AuthenticationMagicAuthSucceededPayload, + AuthenticationMfaFailedPayload, AuthenticationMfaSucceededPayload, AuthenticationOauthFailedPayload, AuthenticationOauthSucceededPayload, + AuthenticationPasskeyFailedPayload, + AuthenticationPasskeySucceededPayload, AuthenticationPasswordFailedPayload, AuthenticationPasswordSucceededPayload, + AuthenticationRadarRiskDetectedPayload, AuthenticationSsoFailedPayload, AuthenticationSsoSucceededPayload, ) from workos.types.events.connection_payload_with_legacy_fields import ( ConnectionPayloadWithLegacyFields, ) +from workos.types.events.connection_saml_certificate_payload import ( + ConnectionSamlCertificateRenewedPayload, + ConnectionSamlCertificateRenewalRequiredPayload, +) from workos.types.events.directory_group_membership_payload import ( DirectoryGroupMembershipPayload, ) @@ -33,9 +43,12 @@ from workos.types.events.directory_user_with_previous_attributes import ( DirectoryUserWithPreviousAttributes, ) +from workos.types.events.flag_payload import FlagPayload from workos.types.events.organization_domain_verification_failed_payload import ( OrganizationDomainVerificationFailedPayload, ) +from workos.types.events.organization_role_payload import OrganizationRolePayload +from workos.types.events.permission_payload import PermissionPayload from workos.types.events.session_payload import ( SessionCreatedPayload, SessionRevokedPayload, @@ -58,6 +71,20 @@ # added to the Webhook union type at the bottom of this file. +class ApiKeyCreatedWebhook(WebhookModel[ApiKeyPayload]): + event: Literal["api_key.created"] + + +class ApiKeyRevokedWebhook(WebhookModel[ApiKeyPayload]): + event: Literal["api_key.revoked"] + + +class AuthenticationEmailVerificationFailedWebhook( + WebhookModel[AuthenticationEmailVerificationFailedPayload,] +): + event: Literal["authentication.email_verification_failed"] + + class AuthenticationEmailVerificationSucceededWebhook( WebhookModel[AuthenticationEmailVerificationSucceededPayload,] ): @@ -76,6 +103,10 @@ class AuthenticationMagicAuthSucceededWebhook( event: Literal["authentication.magic_auth_succeeded"] +class AuthenticationMfaFailedWebhook(WebhookModel[AuthenticationMfaFailedPayload]): + event: Literal["authentication.mfa_failed"] + + class AuthenticationMfaSucceededWebhook( WebhookModel[AuthenticationMfaSucceededPayload] ): @@ -92,6 +123,18 @@ class AuthenticationOauthSucceededWebhook( event: Literal["authentication.oauth_succeeded"] +class AuthenticationPasskeyFailedWebhook( + WebhookModel[AuthenticationPasskeyFailedPayload] +): + event: Literal["authentication.passkey_failed"] + + +class AuthenticationPasskeySucceededWebhook( + WebhookModel[AuthenticationPasskeySucceededPayload] +): + event: Literal["authentication.passkey_succeeded"] + + class AuthenticationPasswordFailedWebhook( WebhookModel[AuthenticationPasswordFailedPayload] ): @@ -104,6 +147,12 @@ class AuthenticationPasswordSucceededWebhook( event: Literal["authentication.password_succeeded"] +class AuthenticationRadarRiskDetectedWebhook( + WebhookModel[AuthenticationRadarRiskDetectedPayload] +): + event: Literal["authentication.radar_risk_detected"] + + class AuthenticationSsoFailedWebhook(WebhookModel[AuthenticationSsoFailedPayload]): event: Literal["authentication.sso_failed"] @@ -126,6 +175,18 @@ class ConnectionDeletedWebhook(WebhookModel[Connection]): event: Literal["connection.deleted"] +class ConnectionSamlCertificateRenewedWebhook( + WebhookModel[ConnectionSamlCertificateRenewedPayload] +): + event: Literal["connection.saml_certificate_renewed"] + + +class ConnectionSamlCertificateRenewalRequiredWebhook( + WebhookModel[ConnectionSamlCertificateRenewalRequiredPayload] +): + event: Literal["connection.saml_certificate_renewal_required"] + + class DirectoryActivatedWebhook(WebhookModel[DirectoryPayloadWithLegacyFields]): event: Literal["dsync.activated"] @@ -172,6 +233,22 @@ class EmailVerificationCreatedWebhook(WebhookModel[EmailVerificationCommon]): event: Literal["email_verification.created"] +class FlagCreatedWebhook(WebhookModel[FlagPayload]): + event: Literal["flag.created"] + + +class FlagDeletedWebhook(WebhookModel[FlagPayload]): + event: Literal["flag.deleted"] + + +class FlagRuleUpdatedWebhook(WebhookModel[FlagPayload]): + event: Literal["flag.rule_updated"] + + +class FlagUpdatedWebhook(WebhookModel[FlagPayload]): + event: Literal["flag.updated"] + + class InvitationAcceptedWebhook(WebhookModel[InvitationCommon]): event: Literal["invitation.accepted"] @@ -180,6 +257,10 @@ class InvitationCreatedWebhook(WebhookModel[InvitationCommon]): event: Literal["invitation.created"] +class InvitationResentWebhook(WebhookModel[InvitationCommon]): + event: Literal["invitation.resent"] + + class InvitationRevokedWebhook(WebhookModel[InvitationCommon]): event: Literal["invitation.revoked"] @@ -234,6 +315,18 @@ class OrganizationMembershipUpdatedWebhook(WebhookModel[OrganizationMembership]) event: Literal["organization_membership.updated"] +class OrganizationRoleCreatedWebhook(WebhookModel[OrganizationRolePayload]): + event: Literal["organization_role.created"] + + +class OrganizationRoleDeletedWebhook(WebhookModel[OrganizationRolePayload]): + event: Literal["organization_role.deleted"] + + +class OrganizationRoleUpdatedWebhook(WebhookModel[OrganizationRolePayload]): + event: Literal["organization_role.updated"] + + class PasswordResetCreatedWebhook(WebhookModel[PasswordResetCommon]): event: Literal["password_reset.created"] @@ -242,6 +335,18 @@ class PasswordResetSucceededWebhook(WebhookModel[PasswordResetCommon]): event: Literal["password_reset.succeeded"] +class PermissionCreatedWebhook(WebhookModel[PermissionPayload]): + event: Literal["permission.created"] + + +class PermissionDeletedWebhook(WebhookModel[PermissionPayload]): + event: Literal["permission.deleted"] + + +class PermissionUpdatedWebhook(WebhookModel[PermissionPayload]): + event: Literal["permission.updated"] + + class RoleCreatedWebhook(WebhookModel[EventRole]): event: Literal["role.created"] @@ -276,19 +381,28 @@ class UserUpdatedWebhook(WebhookModel[User]): Webhook = Annotated[ Union[ + ApiKeyCreatedWebhook, + ApiKeyRevokedWebhook, + AuthenticationEmailVerificationFailedWebhook, AuthenticationEmailVerificationSucceededWebhook, AuthenticationMagicAuthFailedWebhook, AuthenticationMagicAuthSucceededWebhook, + AuthenticationMfaFailedWebhook, AuthenticationMfaSucceededWebhook, AuthenticationOauthFailedWebhook, AuthenticationOauthSucceededWebhook, + AuthenticationPasskeyFailedWebhook, + AuthenticationPasskeySucceededWebhook, AuthenticationPasswordFailedWebhook, AuthenticationPasswordSucceededWebhook, + AuthenticationRadarRiskDetectedWebhook, AuthenticationSsoFailedWebhook, AuthenticationSsoSucceededWebhook, ConnectionActivatedWebhook, ConnectionDeactivatedWebhook, ConnectionDeletedWebhook, + ConnectionSamlCertificateRenewedWebhook, + ConnectionSamlCertificateRenewalRequiredWebhook, DirectoryActivatedWebhook, DirectoryDeletedWebhook, DirectoryGroupCreatedWebhook, @@ -300,8 +414,13 @@ class UserUpdatedWebhook(WebhookModel[User]): DirectoryUserAddedToGroupWebhook, DirectoryUserRemovedFromGroupWebhook, EmailVerificationCreatedWebhook, + FlagCreatedWebhook, + FlagDeletedWebhook, + FlagRuleUpdatedWebhook, + FlagUpdatedWebhook, InvitationAcceptedWebhook, InvitationCreatedWebhook, + InvitationResentWebhook, InvitationRevokedWebhook, MagicAuthCreatedWebhook, OrganizationCreatedWebhook, @@ -315,8 +434,14 @@ class UserUpdatedWebhook(WebhookModel[User]): OrganizationMembershipCreatedWebhook, OrganizationMembershipDeletedWebhook, OrganizationMembershipUpdatedWebhook, + OrganizationRoleCreatedWebhook, + OrganizationRoleDeletedWebhook, + OrganizationRoleUpdatedWebhook, PasswordResetCreatedWebhook, PasswordResetSucceededWebhook, + PermissionCreatedWebhook, + PermissionDeletedWebhook, + PermissionUpdatedWebhook, RoleCreatedWebhook, RoleDeletedWebhook, RoleUpdatedWebhook, From 01542a2545e4f32a36f6073f2370ad38892ec9e3 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Thu, 12 Feb 2026 15:27:26 -0500 Subject: [PATCH 2/4] adjust requiredness --- src/workos/types/events/__init__.py | 1 - src/workos/types/events/api_key_payload.py | 19 ------------------- .../types/events/authentication_payload.py | 5 +++-- .../connection_saml_certificate_payload.py | 4 ++-- src/workos/types/events/event.py | 6 +++--- src/workos/types/events/event_model.py | 4 ++-- src/workos/types/events/flag_payload.py | 16 +++++++++++++--- .../types/events/organization_role_payload.py | 2 +- src/workos/types/webhooks/webhook.py | 6 +++--- 9 files changed, 27 insertions(+), 36 deletions(-) delete mode 100644 src/workos/types/events/api_key_payload.py diff --git a/src/workos/types/events/__init__.py b/src/workos/types/events/__init__.py index 848c5455..25a293c1 100644 --- a/src/workos/types/events/__init__.py +++ b/src/workos/types/events/__init__.py @@ -1,4 +1,3 @@ -from .api_key_payload import * from .authentication_payload import * from .connection_payload_with_legacy_fields import * from .connection_saml_certificate_payload import * diff --git a/src/workos/types/events/api_key_payload.py b/src/workos/types/events/api_key_payload.py deleted file mode 100644 index 83e10e8a..00000000 --- a/src/workos/types/events/api_key_payload.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Literal, Optional, Sequence -from workos.types.workos_model import WorkOSModel - - -class ApiKeyOwner(WorkOSModel): - id: str - type: str - - -class ApiKeyPayload(WorkOSModel): - object: Literal["api_key"] - id: str - name: str - owner: ApiKeyOwner - obfuscated_value: str - permissions: Sequence[str] - last_used_at: Optional[str] = None - created_at: str - updated_at: str diff --git a/src/workos/types/events/authentication_payload.py b/src/workos/types/events/authentication_payload.py index 56adcebd..1bf396a0 100644 --- a/src/workos/types/events/authentication_payload.py +++ b/src/workos/types/events/authentication_payload.py @@ -98,6 +98,7 @@ class AuthenticationSsoSucceededPayload(AuthenticationResultSucceeded): class AuthenticationRadarRiskDetectedPayload(AuthenticationResultCommon): auth_method: str action: str - control: str + control: Optional[str] = None blocklist_type: Optional[str] = None - user_id: Optional[str] = None + user_id: str + email: str diff --git a/src/workos/types/events/connection_saml_certificate_payload.py b/src/workos/types/events/connection_saml_certificate_payload.py index badfd042..784aca1d 100644 --- a/src/workos/types/events/connection_saml_certificate_payload.py +++ b/src/workos/types/events/connection_saml_certificate_payload.py @@ -1,4 +1,4 @@ -from typing import Literal +from typing import Literal, Optional from workos.types.workos_model import WorkOSModel SamlCertificateType = Literal["ResponseSigning", "RequestSigning", "ResponseEncryption"] @@ -6,7 +6,7 @@ class SamlCertificateConnection(WorkOSModel): id: str - organization_id: str + organization_id: Optional[str] = None class SamlCertificate(WorkOSModel): diff --git a/src/workos/types/events/event.py b/src/workos/types/events/event.py index 107d24c7..0323c1aa 100644 --- a/src/workos/types/events/event.py +++ b/src/workos/types/events/event.py @@ -4,7 +4,7 @@ from workos.types.user_management import OrganizationMembership, User from workos.types.directory_sync.directory_group import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser -from workos.types.events.api_key_payload import ApiKeyPayload +from workos.types.api_keys import ApiKey from workos.types.events.authentication_payload import ( AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, @@ -71,11 +71,11 @@ # the event name is added to the EventType union type in event_type.py. -class ApiKeyCreatedEvent(EventModel[ApiKeyPayload]): +class ApiKeyCreatedEvent(EventModel[ApiKey]): event: Literal["api_key.created"] -class ApiKeyRevokedEvent(EventModel[ApiKeyPayload]): +class ApiKeyRevokedEvent(EventModel[ApiKey]): event: Literal["api_key.revoked"] diff --git a/src/workos/types/events/event_model.py b/src/workos/types/events/event_model.py index a20a5ab1..d010e004 100644 --- a/src/workos/types/events/event_model.py +++ b/src/workos/types/events/event_model.py @@ -3,7 +3,7 @@ from workos.types.workos_model import WorkOSModel from workos.types.directory_sync.directory_group import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser -from workos.types.events.api_key_payload import ApiKeyPayload +from workos.types.api_keys import ApiKey from workos.types.events.authentication_payload import ( AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, @@ -67,7 +67,7 @@ EventPayload = TypeVar( "EventPayload", - ApiKeyPayload, + ApiKey, AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, AuthenticationMagicAuthFailedPayload, diff --git a/src/workos/types/events/flag_payload.py b/src/workos/types/events/flag_payload.py index c933379b..6fccd4c0 100644 --- a/src/workos/types/events/flag_payload.py +++ b/src/workos/types/events/flag_payload.py @@ -3,12 +3,22 @@ from workos.types.workos_model import WorkOSModel +class FlagOwner(WorkOSModel): + email: str + first_name: Optional[str] = None + last_name: Optional[str] = None + + class FlagPayload(WorkOSModel): - object: Literal["flag"] + object: Literal["feature_flag"] id: str - name: str + environment_id: str slug: str + name: str description: Optional[str] = None - tags: Optional[Sequence[str]] = None + owner: Optional[FlagOwner] = None + tags: Sequence[str] + enabled: bool + default_value: bool created_at: str updated_at: str diff --git a/src/workos/types/events/organization_role_payload.py b/src/workos/types/events/organization_role_payload.py index 162c3fe1..e257baff 100644 --- a/src/workos/types/events/organization_role_payload.py +++ b/src/workos/types/events/organization_role_payload.py @@ -8,7 +8,7 @@ class OrganizationRolePayload(WorkOSModel): slug: str name: str description: Optional[str] = None - resource_type_slug: Optional[str] = None + resource_type_slug: str permissions: Sequence[str] created_at: str updated_at: str diff --git a/src/workos/types/webhooks/webhook.py b/src/workos/types/webhooks/webhook.py index e218bed8..bba25ad6 100644 --- a/src/workos/types/webhooks/webhook.py +++ b/src/workos/types/webhooks/webhook.py @@ -5,7 +5,7 @@ from workos.types.directory_sync import DirectoryGroup from workos.types.directory_sync.directory_user import DirectoryUser -from workos.types.events.api_key_payload import ApiKeyPayload +from workos.types.api_keys import ApiKey from workos.types.events.authentication_payload import ( AuthenticationEmailVerificationFailedPayload, AuthenticationEmailVerificationSucceededPayload, @@ -71,11 +71,11 @@ # added to the Webhook union type at the bottom of this file. -class ApiKeyCreatedWebhook(WebhookModel[ApiKeyPayload]): +class ApiKeyCreatedWebhook(WebhookModel[ApiKey]): event: Literal["api_key.created"] -class ApiKeyRevokedWebhook(WebhookModel[ApiKeyPayload]): +class ApiKeyRevokedWebhook(WebhookModel[ApiKey]): event: Literal["api_key.revoked"] From 7a5663463520aa065c2b38b12a6640daaa089a22 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Thu, 12 Feb 2026 15:42:15 -0500 Subject: [PATCH 3/4] Add context field to flag.rule_updated event and webhook The backend flag.rule_updated event includes a context object (with actor, access_type, configured_targets, and previous_attributes) as a sibling of the data field. Without this, the context was silently dropped during deserialization. Co-Authored-By: Claude Opus 4.6 --- src/workos/types/events/event.py | 3 +- src/workos/types/events/flag_payload.py | 46 +++++++++++++++++++++++++ src/workos/types/webhooks/webhook.py | 3 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/workos/types/events/event.py b/src/workos/types/events/event.py index 0323c1aa..582be909 100644 --- a/src/workos/types/events/event.py +++ b/src/workos/types/events/event.py @@ -43,7 +43,7 @@ DirectoryUserWithPreviousAttributes, ) from workos.types.events.event_model import EventModel -from workos.types.events.flag_payload import FlagPayload +from workos.types.events.flag_payload import FlagPayload, FlagRuleUpdatedContext from workos.types.events.organization_domain_verification_failed_payload import ( OrganizationDomainVerificationFailedPayload, ) @@ -235,6 +235,7 @@ class FlagDeletedEvent(EventModel[FlagPayload]): class FlagRuleUpdatedEvent(EventModel[FlagPayload]): event: Literal["flag.rule_updated"] + context: FlagRuleUpdatedContext class FlagUpdatedEvent(EventModel[FlagPayload]): diff --git a/src/workos/types/events/flag_payload.py b/src/workos/types/events/flag_payload.py index 6fccd4c0..b382990f 100644 --- a/src/workos/types/events/flag_payload.py +++ b/src/workos/types/events/flag_payload.py @@ -2,6 +2,8 @@ from workos.types.workos_model import WorkOSModel +AccessType = Literal["none", "some", "all"] + class FlagOwner(WorkOSModel): email: str @@ -22,3 +24,47 @@ class FlagPayload(WorkOSModel): default_value: bool created_at: str updated_at: str + + +class FlagRuleActor(WorkOSModel): + id: str + source: Literal["api", "dashboard", "system"] + name: Optional[str] = None + + +class FlagRuleOrganizationTarget(WorkOSModel): + id: str + name: str + + +class FlagRuleUserTarget(WorkOSModel): + id: str + email: str + + +class FlagRuleConfiguredTargets(WorkOSModel): + organizations: Sequence[FlagRuleOrganizationTarget] + users: Sequence[FlagRuleUserTarget] + + +class FlagRulePreviousDataAttributes(WorkOSModel): + enabled: Optional[bool] = None + default_value: Optional[bool] = None + + +class FlagRulePreviousContextAttributes(WorkOSModel): + access_type: Optional[AccessType] = None + configured_targets: Optional[FlagRuleConfiguredTargets] = None + + +class FlagRulePreviousAttributes(WorkOSModel): + data: Optional[FlagRulePreviousDataAttributes] = None + context: Optional[FlagRulePreviousContextAttributes] = None + + +class FlagRuleUpdatedContext(WorkOSModel): + client_id: str + actor: FlagRuleActor + access_type: AccessType + configured_targets: FlagRuleConfiguredTargets + previous_attributes: FlagRulePreviousAttributes diff --git a/src/workos/types/webhooks/webhook.py b/src/workos/types/webhooks/webhook.py index bba25ad6..fa2a47b0 100644 --- a/src/workos/types/webhooks/webhook.py +++ b/src/workos/types/webhooks/webhook.py @@ -43,7 +43,7 @@ from workos.types.events.directory_user_with_previous_attributes import ( DirectoryUserWithPreviousAttributes, ) -from workos.types.events.flag_payload import FlagPayload +from workos.types.events.flag_payload import FlagPayload, FlagRuleUpdatedContext from workos.types.events.organization_domain_verification_failed_payload import ( OrganizationDomainVerificationFailedPayload, ) @@ -243,6 +243,7 @@ class FlagDeletedWebhook(WebhookModel[FlagPayload]): class FlagRuleUpdatedWebhook(WebhookModel[FlagPayload]): event: Literal["flag.rule_updated"] + context: FlagRuleUpdatedContext class FlagUpdatedWebhook(WebhookModel[FlagPayload]): From 66bd6b7b321f6296d3c4b0d76a26f6d14b0d38c3 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Thu, 12 Feb 2026 15:44:25 -0500 Subject: [PATCH 4/4] Make sso field required on SSO auth event payloads Co-Authored-By: Claude Opus 4.6 --- src/workos/types/events/authentication_payload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workos/types/events/authentication_payload.py b/src/workos/types/events/authentication_payload.py index 1bf396a0..05ebe02e 100644 --- a/src/workos/types/events/authentication_payload.py +++ b/src/workos/types/events/authentication_payload.py @@ -86,13 +86,13 @@ class AuthenticationSsoData(WorkOSModel): class AuthenticationSsoFailedPayload(AuthenticationResultFailed): type: Literal["sso"] - sso: Optional[AuthenticationSsoData] = None + sso: AuthenticationSsoData class AuthenticationSsoSucceededPayload(AuthenticationResultSucceeded): type: Literal["sso"] user_id: Optional[str] = None - sso: Optional[AuthenticationSsoData] = None + sso: AuthenticationSsoData class AuthenticationRadarRiskDetectedPayload(AuthenticationResultCommon):