---
title: Notify when a deployment fully shifts traffic
description: "\U0001F3AF  React to deployments only when they reach 100% traffic, the moment your scope is fully on the new revision."
sidebar_label: Notify on full traffic shift
doc_id: c1b8ad6e-6e05-4fb6-80c8-3c26a002c61b
tutorial_type: tutorial
tutorial_category: automation
tutorial_time: 10 min
tutorial_featured: false
tutorial_cover: /img/tutorials/covers/notify-on-deployment-traffic-shift.svg
keywords:
  - entity hooks
  - deployments
  - notification channels
  - filters
  - traffic shift
  - finalized
tags:
  - entity_hooks
  - automation
  - production
---

# Notify when a deployment fully shifts traffic

> 🎯 **Goal:** Run custom logic the instant a deployment is fully serving production traffic, not on every intermediate update.

## Introduction

Deployment updates fire often during a rollout: progress percentages, health checks, traffic switch increments, and a final status change. Most of the time you don't want to react to all of them. You want one signal that says *"this deployment is now the live one."*

The pattern: create an entity hook that subscribes to `deployment:write` events, then attach a notification channel that filters on the request body, so your endpoint only sees the events where traffic actually moved to 100%. The hook itself stays generic; the channel does the filtering. See [Conditional hook firing](/docs/entity-hooks/filters) for the underlying mechanism.

## When you'd use this hook

This pattern is useful any time the action you want to take has to happen *after* users are actually being served by the new revision, not during the rollout, and not on every intermediate progress update. A few concrete examples:

- **Run a post-deploy test suite.** Kick off smoke tests, synthetic monitoring, or end-to-end checks the moment 100% of traffic is on the new revision, so you measure the version your users are hitting.
- **Close out the Jira ticket attached to the deployment.** Move the issue to *Done*, post a comment with the deployment URL, or update a custom "Released in" field, automatically, only once the rollout is complete.
- **Trigger customer-facing announcements.** Drop a release note in a status page, post to a `#changelog` Slack channel, or email a customer segment that the feature they were waiting on is now live everywhere.

The common thread: each of these is a one-shot action that should fire exactly once per deployment, when the new version is fully live.

## What you'll set up

By the end of this guide, you'll have:

- An **after-hook** on `deployment:write` that intercepts every update
- A notification channel with `filters` that only forwards the events you care about (we cover two options: traffic-100 only, or traffic-100 plus finalized-status fallback)

## 1. Create the hook action

The hook subscribes to deployment updates. It carries no filtering of its own: every update will trigger the hook internally; the channel decides what reaches you.

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

- **`when: "after"`**: the hook runs after nullplatform has already applied the update, which is the right place to react to a settled state.
- **`on: "update"`**: only fires for updates, not creates or deletes.

## 2. Create the notification channel

The filter lives here, on the notification channel. The framework injects the request body into the notification's `context.request_body`, and channel filters are evaluated against the `context` object, so filter paths start with `request_body.<field>` (no `context.` prefix).

You have two options, depending on how strict you want the "deployment is done" signal to be:

- **Option A** matches only when traffic reaches exactly 100%. Simpler, but skips fast-finalize cases.
- **Option B** matches traffic-100 *or* a finalized status. Broader, but requires an idempotent handler.

### Option A: Only on full traffic shift

```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
    }
  }'
```

That's it. Every deployment update still triggers the hook, but the channel only delivers the ones where `strategy_data.switched_traffic` equals exactly `100`. Your endpoint will only see "done" events.

:::warning Watch out for fast finalizations
Some deployment strategies finalize a deployment **without** going through a 100% traffic shift. For example, if the rollout is aborted and rolled back, or if a strategy completes by promoting the revision in a single step. In those cases, `strategy_data.switched_traffic` may never be exactly `100`, and the channel above will silently skip the event.

If you need to react to *every* "this deployment is now done" signal regardless of how it finished, use the broader filter below instead.
:::

### Option B: Cover both traffic-100 and finalized statuses

To catch both the traffic-shift case and the fast-finalize case, combine the conditions with `$or` on the channel filter:

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

Now the channel forwards when **either** condition holds. The trade-off: a deployment that goes through a normal rollout will hit this channel twice, once when traffic reaches 100 and once when the status transitions to `finalized`. Make sure your handler is idempotent (or de-duplicate by `notification.entity_id` on your side) before relying on this filter in production.

## 3. Implement the handler

Once both the hook and the channel are in place, nullplatform starts delivering filtered notifications. The payload your endpoint receives looks like this:

```json title="POST https://yourdomain.com/deployment-finalized"
{
  "id": "1180cd02-1c36-4274-8e7a-4483b87e8f2e",
  "source": "entity",
  "event": "deployment:write",
  "created_at": "2026-05-19T14:20:43.088Z",
  "notification": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "entity": "deployment",
    "entity_id": "5",
    "nrn": "organization=1:account=2:namespace=3:application=4:scope=5",
    "callback_url": "https://api.nullplatform.com/entity_hook/550e8400-e29b-41d4-a716-446655440000",
    "type": "hook",
    "when": "after",
    "on": "update",
    "request_body": {
      "status": "finalized", // present if you're using the status filter (Option B)
      "strategy_data": { "switched_traffic": 100 }
    }
  }
}
```

For an after-hook, nullplatform expects an acknowledgement. See [Implementing hook processing](/docs/entity-hooks/#3-implement-hook-processing) for the full callback format.

## Where to go next

- [Conditional hook firing](/docs/entity-hooks/filters): the mechanism behind channel-side filtering for hooks
- [Notification filters reference](/docs/notifications/filters): full operator list and dot-notation rules
- [Entity hooks overview](/docs/entity-hooks): before vs after hooks, approvals interaction, and lifecycle states
