# Rule-Triggered Webhooks

Use the Rule Builder to receive a webhook only when a chosen condition matches — for example a specific harm label. Stream sends [`moderation_rule.triggered`](https://getstream.io/moderation/docs/node/content-moderation/webhooks/#moderation_ruletriggered) for that rule. Other messages do not produce this event.

This is the scoped alternative to subscribing to every review-queue item. Pair it with `webhook_only` when you want a notification, or with a user/content action when you also want Stream to enforce something.

## How it works

1. Create a [rule](https://getstream.io/moderation/docs/node/configuration/rules/) whose conditions describe the harms (or other signals) you care about.
2. Set the rule action to `webhook_only`, or to a user/content action such as `flag_user`.
3. Subscribe an event hook to `moderation_rule.triggered` with product `moderation`.

When a check evaluates that rule and the conditions pass, Stream sends one `moderation_rule.triggered` event. Rule actions run in addition to the action already configured on the policy for that label.

## Content rule: notify on a harm label

A `content` rule with `text_content` evaluates the current message, activity, or comment. It fires as soon as the listed labels are present.

```json
{
  "name": "High-profile harms",
  "description": "Notify when selected harm labels are detected",
  "rule_type": "content",
  "enabled": true,
  "config_keys": ["chat:messaging", "chat:livestream"],
  "conditions": [
    {
      "type": "text_content",
      "text_content_params": {
        "harm_labels": ["UNDERAGE_USER", "SCAM"]
      }
    }
  ],
  "action": {
    "type": "webhook_only"
  }
}
```

| Field                             | Description                                                                       |
| --------------------------------- | --------------------------------------------------------------------------------- |
| `rule_type`                       | `"content"` evaluates the current piece of content.                               |
| `config_keys`                     | Policies this rule applies to. An empty list applies the rule app-wide.           |
| `text_content_params.harm_labels` | Labels that satisfy the condition. Any listed label is enough.                    |
| `text_content_params.severity`    | Optional minimum severity (`LOW`, `MEDIUM`, `HIGH`, `CRITICAL`).                  |
| `action.type`                     | `"webhook_only"` sends the event and does not apply a further enforcement action. |

Create or update the rule with `POST /api/v2/moderation/moderation_rule`. Enable the Rule Builder on the same config:

```json
{
  "key": "chat:messaging",
  "rule_builder_config": {
    "enabled": true
  }
}
```

```js label="Node.js"
await client.moderation.upsertConfig({
  key: "chat:messaging",
  rule_builder_config: { enabled: true },
});

await client.moderation.upsertModerationRule({
  name: "High-profile harms",
  description: "Notify when selected harm labels are detected",
  config_keys: ["chat:messaging", "chat:livestream"],
  enabled: true,
  rule_type: "content",
  conditions: [
    {
      type: "text_content",
      text_content_params: {
        harm_labels: ["UNDERAGE_USER", "SCAM"],
      },
    },
  ],
  action: { type: "webhook_only" },
});
```

Other conditions on a content rule work the same way: `blocklist_match`, `contains_url`, image `harm_labels`, and so on. See [Rules](https://getstream.io/moderation/docs/node/configuration/rules/).

## User rule: act on the account

A `user` rule with `text_rule` counts matching labels for one user over a time window. Use this when the signal should follow the account rather than a single piece of content.

```json
{
  "name": "Repeat high-severity insult",
  "rule_type": "user",
  "enabled": true,
  "config_keys": ["chat:messaging"],
  "conditions": [
    {
      "type": "text_rule",
      "text_rule_params": {
        "threshold": 1,
        "time_window": "1h",
        "harm_labels": ["INSULT"],
        "severity": "HIGH"
      }
    }
  ],
  "action": {
    "type": "flag_user"
  }
}
```

`threshold: 1` fires on the first matching message. Increase it to require a repeated pattern. The same `moderation_rule.triggered` event is sent when the rule fires.

## Subscribe to the event

Configure the hook in the [dashboard](https://getstream.io/signin/?product=moderation) (**Moderation → Preferences → Webhook & SNS/SQS**) or via `event_hooks` on the app:

```json
{
  "hook_type": "webhook",
  "enabled": true,
  "product": "moderation",
  "event_types": ["moderation_rule.triggered"],
  "webhook_url": "https://example.com/moderation/rules"
}
```

`product` must be `moderation` (or `all`). If `event_types` omits `moderation_rule.triggered`, the event is dropped.

## Event payload

```json
{
  "type": "moderation_rule.triggered",
  "created_at": "2026-09-14T11:00:54.928472211Z",
  "rule": {
    "id": "5423c4d3-d4f0-4264-85a9-e176c9915477",
    "name": "High-profile harms",
    "type": "content",
    "description": "Notify when selected harm labels are detected"
  },
  "entity_id": "85f3c2a1-9c4e-4b1d-8a77-2f0e91c4d123",
  "entity_type": "stream:chat:v1:message",
  "user_id": "user-42",
  "triggered_actions": ["webhook_only"]
}
```

| Field                  | Description                                                                                                                                                                                                           |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                 | Always `moderation_rule.triggered`.                                                                                                                                                                                   |
| `created_at`           | When the rule fired.                                                                                                                                                                                                  |
| `rule.id`              | Rule ID.                                                                                                                                                                                                              |
| `rule.name`            | Rule name.                                                                                                                                                                                                            |
| `rule.type`            | `content`, `user`, or `call`.                                                                                                                                                                                         |
| `rule.description`     | Rule description.                                                                                                                                                                                                     |
| `entity_id`            | ID of the entity that triggered the rule. For chat this is the message ID. For Feeds v3 this is the activity or comment ID. For calls this is the call CID.                                                           |
| `entity_type`          | Entity type. Common values: `stream:chat:v1:message`, `stream:feeds:v3:activity`, `stream:feeds:v3:comment`, `stream:v1:call`.                                                                                        |
| `user_id`              | ID of the user who created the entity.                                                                                                                                                                                |
| `triggered_actions`    | Actions the rule executed, for example `["webhook_only"]` or `["flag_user"]`.                                                                                                                                         |
| `review_queue_item_id` | Review-queue item ID when one is associated with the event.                                                                                                                                                           |
| `violation_number`     | Present on call rules with action sequences.                                                                                                                                                                          |
| `matched_contents`     | Present on aggregation rules (keyframes, closed captions, keyframe OCR) when the request supplied `content_ids`. Each entry includes `type`, `id`, `published_at`, and the classifications or severity for that item. |

One event is sent per rule per entity (and per `violation_number` on call rules).

## Related events

| Event                        | When it fires                                                                                                                        |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `moderation_rule.triggered`  | A Rule Builder rule matched. Use this for label-scoped or condition-scoped notifications.                                            |
| `review_queue_item.new`      | A review-queue item is created. The payload includes the item, flags, and the enriched entity (message, activity, comment, or call). |
| `review_queue_item.updated`  | An existing item receives more flags or a moderator action.                                                                          |
| `moderation_check.completed` | A moderation check finished, including when the recommended action is `keep`.                                                        |

See [Webhooks](https://getstream.io/moderation/docs/node/content-moderation/webhooks/) for the full payload of each event.

---

For the most recent version of this documentation, visit [https://getstream.io/moderation/docs/node/guides/rule-triggered-webhooks/](https://getstream.io/moderation/docs/node/guides/rule-triggered-webhooks/).