# organizationMembership.created: the join event

Fires when a user becomes a member of an organization, by invitation acceptance, admin add, or self-join depending on your settings.

## What to do on receipt

1. Read the three nested pieces:
   - Org: `evt.data.organization.id` (and `name` for display)
   - User: `evt.data.public_user_data.user_id`
   - Role: `evt.data.role`, e.g. `org:admin` or `org:member`
2. Create the membership row in your app keyed by org id plus user id. Grant the entitlements that match the role.
3. If you provision per-seat resources or count seats for billing, increment here. This event is your seat counter's source of truth.
4. Return 200.

## The trap

Reading the payload flat. Agents sometimes look for `evt.data.user_id` or `evt.data.organization_id` at the top level and get undefined. The membership payload nests: organization under `organization`, the user under `public_user_data`, the role as `role`. Destructure the nesting deliberately.

## Checklist

- The user behind `public_user_data.user_id` already exists in Clerk; make sure your user sync (the user trio) has run or handle a missing user row with an upsert.
- Invitation acceptances arrive as `organizationInvitation.accepted` AND then this event. Do not double-provision: the membership event is the one that grants access.
- Roles are strings like `org:admin`. Compare against the exact role key, not a substring.