# Webhook events

> Every webhook event type, when it is sent, and the data it carries.

Source: https://9in.io/docs/reference/webhook-events/

Every webhook is a `POST` with this JSON body (JSON Schema: [/schemas/webhook-event.json](https://9in.io/schemas/webhook-event.json)):

```json
{
  "id": "evt_…",
  "type": "user.created",
  "createdAt": "2026-11-09T08:00:00.000Z",
  "tenant": "tnt_…",
  "environment": "production",
  "data": { … }
}
```

For events about a user, `data` also has `userId` and `user`, a snapshot of the user as the [Management API](https://9in.io/docs/reference/management-api/#the-user-object) returns it (`null` once deleted). Headers: `9in-signature`, `9in-event-id`, `9in-event-type`, `9in-delivery-id`. How to verify and process them: [Webhooks](https://9in.io/docs/webhooks/).

## Users

| Event | When | `data` (besides `userId`, `user`) |
|---|---|---|
| `user.created` | A user was created: sign-up, first social or enterprise sign-in, the console or the API | |
| `user.updated` | Profile, identifiers, metadata or the blocked flag changed | `fields`: the names that changed |
| `user.deleted` | The user was deleted | |
| `user.password_changed` | A password was set, reset or changed | `reason`: `set`, `reset` or `import` |

## Sign-in

| Event | When | `data` |
|---|---|---|
| `user.login` | Someone signed in | `method` (`pwd`, `otp`, `social`, `fed`, `link`, joined with `+` and `mfa`, e.g. `pwd+mfa`), `ip`, `client`, and `grant` for the password grant |
| `user.login_failed` | A sign-in failed | `reason` (e.g. `invalid_credentials`, `mfa_invalid_code`), `method`, `ip`, `client`; `userId` is null |
| `user.sessions_revoked` | All of a user's sessions were ended (sign out everywhere, an admin, the API) | `count` |

## Sessions and tokens

| Event | When | `data` |
|---|---|---|
| `session.revoked` | One session ended (sign-out, the account page, an admin, the API) | `sid` |
| `token.revoked` | A refresh or access token was revoked | `type` (`refresh_token` or `access_token`), `clientId`, `sid`, and `jti` for access tokens |

APIs using [hybrid verification](https://9in.io/docs/protecting-apis/#hybrid-recommended) pass these to `verifier.handleEvent()`.

## Two-factor

| Event | When | `data` |
|---|---|---|
| `user.mfa_enabled` | The user set up an authenticator app | |
| `user.mfa_disabled` | Two-factor was turned off | `by`: `user` or `admin` |

## Testing

| Event | When |
|---|---|
| `webhook.test` | You pressed **Send test** on an endpoint in the console |

Events are delivered at least once and not necessarily in order; the same event `id` repeats on retries and redeliveries.
