> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Security & IAM Webhook Events

> Receive real-time notifications for authentication, members, roles, and security settings — for SIEM and security monitoring integrations.

## Overview

Security webhook events notify your SIEM or security tooling when identity and access management (IAM) actions occur in Gu1: member lifecycle, role changes, sign-in/out, failed logins, admin password actions, and selected security settings.

Configure them like any other webhook in **Settings → Webhooks** and subscribe only to the `security.*` events you need.

## Payload Shape (All Security Events)

Every security webhook uses the standard envelope plus a normalized inner payload:

```json theme={null}
{
  "event": "security.auth.login_succeeded",
  "timestamp": "2026-06-18T12:00:00.000Z",
  "organizationId": "550e8400-e29b-41d4-a716-446655440000",
  "payload": {
    "actionAt": "2026-06-18T12:00:00.000Z",
    "actor": {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "email": "admin@example.com",
      "displayName": "Jane Admin"
    },
    "affectedUser": {
      "id": "550e8400-e29b-41d4-a716-446655440002",
      "email": "user@example.com",
      "displayName": "John User"
    },
    "description": "User logged in successfully",
    "changes": {
      "permissions": {
        "added": ["entities:write"],
        "removed": [],
        "current": ["entities:read", "entities:write"]
      }
    },
    "context": {
      "ipAddress": "203.0.113.10",
      "userAgent": "Mozilla/5.0 ...",
      "scope": "sandbox",
      "roleId": "uuid",
      "roleName": "Analyst"
    }
  }
}
```

| Field          | Description                                                                                                    |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| `actionAt`     | When the action occurred (ISO 8601)                                                                            |
| `actor`        | User who performed the action (`id` is Gu1 DB UUID when available)                                             |
| `affectedUser` | User impacted by the action (when applicable)                                                                  |
| `description`  | Human-readable summary                                                                                         |
| `changes`      | Map of changed fields. Role permissions: `{ added, removed, current }`. Other fields: `{ previous, current }`. |
| `context`      | IP, user agent, settings scope, role metadata                                                                  |

## Available Events

### Members (`security.member.*`)

| Event                                 | When it fires                                                                              |
| ------------------------------------- | ------------------------------------------------------------------------------------------ |
| `security.member.invited`             | Admin invites a new member                                                                 |
| `security.member.created`             | Member accepts invitation / is created in org                                              |
| `security.member.removed`             | Member removed from organization                                                           |
| `security.member.activated`           | Member enabled / reactivated                                                               |
| `security.member.deactivated`         | Member disabled                                                                            |
| `security.member.profile_updated`     | Admin updates member display name (`firstName` / `lastName`)                               |
| `security.member.password_reset`      | Admin resets a member's password                                                           |
| `security.member.password_generated`  | Admin generates a temporary password                                                       |
| `security.member.team_added`          | Member is added to a team                                                                  |
| `security.member.team_removed`        | Member is removed from a team                                                              |
| `security.member.team_role_changed`   | Member's role within a team changes                                                        |
| `security.member.channel_granted`     | Member is granted access to a child channel organization                                   |
| `security.member.channel_revoked`     | Member's access to a child channel organization is revoked                                 |
| `security.member.environment_granted` | Member is granted access to the paired production or sandbox org                           |
| `security.member.environment_revoked` | Member's access to the paired production or sandbox org is revoked                         |
| `security.member.environment_changed` | Admin changes a member's production/sandbox access in one step (`fromAccess` → `toAccess`) |

`context.teamType` (e.g. `production`, `sandbox`) and `context.teamRole` apply to team events. For environment access, `context.environment` is `"production"` or `"sandbox"`, with `context.environmentOrganizationId` and `context.environmentOrganizationName`. On `security.member.environment_changed`, use `context.fromAccess` / `context.toAccess` (`"both"` | `"production"` | `"sandbox"` | `"none"`) and `changes.environmentAccess`. Channel webhooks fire on the **parent organization** context; `context.channelOrganizationId` identifies the channel.

#### Invitation lifecycle (`security.member.invited` → `security.member.created`)

If you subscribe to both events, expect **two separate deliveries** in this order:

| Event                     | When Gu1 sends it                                                                     | `organizationId` in the envelope            |
| ------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------- |
| `security.member.invited` | When an admin sends the invitation from Gu1 (Teams / invite flow)                     | Organization where the invitation is issued |
| `security.member.created` | After the invitee completes signup and membership is established in that organization | Same organization as the invitation         |

**Integrator expectations:**

* **Do not** expect `security.member.created` at the same time as `security.member.invited`. The invitee must accept first; delivery is typically seconds to minutes later.
* On `security.member.created`, `actor` and `affectedUser` usually refer to the **new member** (same Gu1 user UUID). `affectedUser.email` is the invited address.
* `payload.description` is normally `"Member accepted organization invitation"`. In rare cases where secondary setup (paired sandbox access, granular roles, or team assignment) could not be fully applied in the same pass, the description may read `"Member accepted organization invitation (environment sync incomplete)"`. The member still has access in the invitation organization context — treat the webhook as a successful member creation for SIEM and access-governance use cases.
* If you receive `invited` but never `created` after the user confirms they joined Gu1, check that your endpoint returned HTTP 2xx when Gu1 delivered events around acceptance time, then contact Gu1 support with the approximate timestamp and `organizationId`.
* Use `payload.context.invitationId` to correlate `invited` and `created` for the same invite (same UUID on both events when acceptance succeeds).

**Invitation `context` fields** (present on `security.member.invited` and `security.member.created` when applicable):

| Field                    | Type    | Description                                                                                                                                                                                                                         |
| ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invitationId`           | UUID    | Gu1 invitation record — use to correlate invited → created                                                                                                                                                                          |
| `granularRoleIds`        | UUID\[] | Granular role IDs for the production org                                                                                                                                                                                            |
| `granularRoleIdsSandbox` | UUID\[] | Granular role IDs for the paired sandbox org                                                                                                                                                                                        |
| `includeProduction`      | boolean | Invitation grants production access                                                                                                                                                                                                 |
| `includeSandbox`         | boolean | Invitation grants sandbox access                                                                                                                                                                                                    |
| `teamId`                 | UUID    | Production team assigned on acceptance                                                                                                                                                                                              |
| `teamIdSandbox`          | UUID    | Sandbox team assigned on acceptance                                                                                                                                                                                                 |
| `hasEnvironmentAccess`   | boolean | Whether the member can **enter** that environment (`organization_members.has_environment_access`). Independent of granular roles and teams, which are always provisioned from the invitation for both prod and sandbox when defined |
| `environment`            | string  | `"production"` or `"sandbox"` for the org in the envelope                                                                                                                                                                           |
| `invitedByUserId`        | UUID    | Gu1 user who sent the invitation                                                                                                                                                                                                    |
| `acceptedVia`            | string  | On `created`: `"invitation"` when the member joined via invite                                                                                                                                                                      |
| `syncPartialFailure`     | boolean | On `created` only: secondary setup (sandbox, granular roles, teams) did not fully complete                                                                                                                                          |
| `syncErrorMessage`       | string  | On `created` when `syncPartialFailure` is true: internal error summary                                                                                                                                                              |

Example `security.member.invited` payload:

```json theme={null}
{
  "event": "security.member.invited",
  "timestamp": "2026-06-18T12:00:00.000Z",
  "organizationId": "550e8400-e29b-41d4-a716-446655440000",
  "payload": {
    "actionAt": "2026-06-18T12:00:00.000Z",
    "actor": {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "email": "admin@example.com",
      "displayName": "Jane Admin"
    },
    "affectedUser": {
      "email": "new@example.com"
    },
    "description": "User invited with role developer",
    "changes": {
      "role": { "previous": null, "current": "developer" }
    },
    "context": {
      "invitationId": "550e8400-e29b-41d4-a716-446655440099",
      "granularRoleIds": ["550e8400-e29b-41d4-a716-446655440011"],
      "granularRoleIdsSandbox": ["550e8400-e29b-41d4-a716-446655440012"],
      "includeProduction": true,
      "includeSandbox": true,
      "teamId": "550e8400-e29b-41d4-a716-446655440010",
      "teamIdSandbox": "550e8400-e29b-41d4-a716-446655440013",
      "hasEnvironmentAccess": true,
      "environment": "production",
      "invitedByUserId": "550e8400-e29b-41d4-a716-446655440001",
      "ipAddress": "203.0.113.10",
      "userAgent": "Mozilla/5.0 ..."
    }
  }
}
```

Example `security.member.created` payload:

```json theme={null}
{
  "event": "security.member.created",
  "timestamp": "2026-06-18T12:05:00.000Z",
  "organizationId": "550e8400-e29b-41d4-a716-446655440000",
  "payload": {
    "actionAt": "2026-06-18T12:05:00.000Z",
    "actor": {
      "id": "550e8400-e29b-41d4-a716-446655440002",
      "email": "new@example.com"
    },
    "affectedUser": {
      "id": "550e8400-e29b-41d4-a716-446655440002",
      "email": "new@example.com"
    },
    "description": "Member accepted organization invitation",
    "context": {
      "invitationId": "550e8400-e29b-41d4-a716-446655440099",
      "granularRoleIds": ["550e8400-e29b-41d4-a716-446655440011"],
      "granularRoleIdsSandbox": ["550e8400-e29b-41d4-a716-446655440012"],
      "includeProduction": true,
      "includeSandbox": true,
      "teamId": "550e8400-e29b-41d4-a716-446655440010",
      "hasEnvironmentAccess": true,
      "environment": "production",
      "acceptedVia": "invitation",
      "invitedByUserId": "550e8400-e29b-41d4-a716-446655440001"
    }
  }
}
```

Related follow-up events (same member, separate webhooks when applicable): `security.member.environment_granted`, `security.member.team_added`, `security.member.channel_granted`, `security.role.assigned`.

### Roles & RBAC (`security.role.*`, `security.rbac.*`)

| Event                            | When it fires                                            |
| -------------------------------- | -------------------------------------------------------- |
| `security.role.created`          | Granular role created                                    |
| `security.role.updated`          | Role modified (includes permission diffs when available) |
| `security.role.deleted`          | Role deleted                                             |
| `security.role.assigned`         | Role assigned to user                                    |
| `security.role.revoked`          | Role revoked from user                                   |
| `security.rbac.granular_toggled` | Granular RBAC enabled or disabled                        |

### Authentication (`security.auth.*`)

| Event                           | When it fires                                          |
| ------------------------------- | ------------------------------------------------------ |
| `security.auth.login_succeeded` | Successful sign-in (Gu1 web app)                       |
| `security.auth.logout`          | User signs out                                         |
| `security.auth.login_failed`    | Failed sign-in attempt (when email resolves to an org) |

### Security Settings

| Event                       | When it fires                                                                                                             |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `security.settings.updated` | Sandbox mode, general/risk settings, or other audited security-related org settings (`context.scope` identifies the area) |

## Limitations

The following are **not** covered by Gu1 security webhooks today:

* End-user **self-service password change** in Clerk (IdP-only)
* MFA / SSO configuration changes in Clerk
* Machine-to-machine **API key** authentication (separate from user login)
* Clerk dashboard session revocations that never touch Gu1 API

Admin-initiated password reset/generation **is** covered via `security.member.password_*`.

## Related

* [Webhooks overview](/en/webhooks/overview)
* [Security & signatures](/en/webhooks/security)
* [Configuration](/en/webhooks/configuration)
