---
sidebar_label: Conditional firing
toc_max_heading_level: 3
doc_id: c7582725-e67b-4d7c-ba3a-035a75eb5c32
description: >-
  Use notification channel filters to fire entity hooks only when the request
  that triggered them matches specific conditions.
keywords:
  - entity hooks
  - filters
  - MongoDB query
  - notification channels
  - request body
  - lifecycle events
---

# Conditional hook firing

By default, an entity hook fires on every matching event for its `nrn`, `entity`, `action`, and `dimensions`. If you want a hook to react only to some of those events (for example, only when a deployment is fully live), you don't filter the hook itself. You filter the **notification channel** that the hook delivers through.

The reason: hooks reach your code by going through a notification channel. nullplatform sends each hook event as a notification, and the channel decides whether to deliver it based on its `filters` field. So the same channel-side filtering you already use for Slack, HTTP, or agent notifications also works for entity hooks.

## Common cases

- *"Only run my deployment hook when the deployment switches traffic to 100%."*
- *"Only run my scope hook when the scope is being stopped."*
- *"Only run my application hook when the application is being imported from an existing repository."*

## How it works

When an entity event triggers a hook, nullplatform builds a notification with this shape and sends it to channels subscribed to the `entity` source:

```json
{
  "nrn": "organization=1:account=2:namespace=3:application=4:scope=5",
  "action": "deployment:update",
  "source": "entity",
  "context": {
    "entity": "deployment",
    "action": "deployment:update",
    "when": "after",
    "on": "update",
    "request_body": {
      "status": "finalized",
      "strategy_data": { "switched_traffic": 100 }
    },
    "tags": { ... }
  }
}
```

The interesting part is `request_body`: it's the exact body of the operation that triggered the hook (the PATCH/POST/DELETE that nullplatform's framework intercepted).

Channel filters are evaluated **against the `context` object**, so when you write a filter expression you reference paths **starting from inside `context`**. No `context.` prefix needed. For example, the path to the request body is just `request_body.<field>`, not `context.request_body.<field>`.

## What you can filter on

The fields you can match on are exactly the request body fields documented in the API reference for the operation that triggered the hook.

| Entity | `on: create` body | `on: update` body |
|---|---|---|
| `application` | [Create an application](/docs/api/application-create) | [Update an application](/docs/api/application-update) |
| `scope` | [Create a scope](/docs/api/scope-create) | [Update a scope](/docs/api/scope-update) |
| `deployment` | [Create a deployment](/docs/api/deployment-create) | [Update a deployment](/docs/api/deployment-update) |

Any field shown in those request bodies is reachable inside `request_body.<field>`, including nested fields via dot notation.

:::tip
For the full filter operator reference (`$eq`, `$in`, `$and`, `$or`, `$gte`, `$regex`, dot notation, and more), see [Notification filters](/docs/notifications/filters). The syntax is shared across nullplatform notification channels.
:::

## Setting up a filtered hook

A filtered hook is two things: the hook action itself (so nullplatform knows to intercept the event) and a channel with the right `filters` (so only the events you care about get delivered).

### 1. Create the hook action

[Create the hook action](/docs/api/entity-hook-action-create) as usual, declaring the event you want to intercept:

```bash
np entity-hook action create \
  --body '{
    "nrn": "<account nrn or namespace nrn>",
    "entity": "deployment",
    "action": "deployment:update",
    "when": "after",
    "type": "hook",
    "on": "update"
  }'
```

No `filters` field on the hook itself: that's intentional. The hook just declares interest in `deployment:update` events; the channel decides which ones get delivered.

### 2. Create a channel with filters

[Create a notification channel](/docs/api/notification-channel-create) subscribed to the `entity` source, with the `filters` that decide which events get delivered:

```bash
np notification channel create \
  --body '{
    "nrn": "<account nrn or namespace nrn>",
    "source": ["entity"],
    "type": "http",
    "configuration": {
      "url": "https://yourdomain.com/deployment-finalized"
    },
    "filters": {
      "request_body.strategy_data.switched_traffic": 100
    }
  }'
```

Now the channel only receives events where the deployment's `strategy_data.switched_traffic` is exactly `100`. Other deployment updates fire the hook internally, but the channel filters them out before delivery.

To check which hooks a given request would trigger once filters are applied, use [Find entity hook actions](/docs/api/entity-hook-action-find) with the request body you plan to send.

## Examples

### Only on full traffic switch

```json
"filters": {
  "request_body.strategy_data.switched_traffic": 100
}
```

### Only on a finalized deployment

```json
"filters": {
  "request_body.status": "finalized"
}
```

### Combine conditions

Fire only when the deployment is finalized **or** the rollout has shifted at least half the traffic:

```json
"filters": {
  "$or": [
    { "request_body.status": "finalized" },
    { "request_body.strategy_data.switched_traffic": { "$gte": 50 } }
  ]
}
```

### Filter on context fields beyond the request body

Channel filters can also match on the rest of the context. For example, only react to *update* events, not *create* or *delete*:

```json
"filters": {
  "on": "update",
  "when": "after"
}
```

## Where to go next

- [Entity hooks overview](/docs/entity-hooks): before/after hooks, approvals interaction, and the response contract
- [Notification filters reference](/docs/notifications/filters): full operator list and syntax shared across nullplatform channels
- [Notify when a deployment fully shifts traffic](/docs/tutorials/notify-on-deployment-traffic-shift): worked tutorial using the pattern from this page
