---
title: Change approval webhooks
slug: feature-experimentation/docs/QZ9N-change-approval-webhooks
docTags: 
createdAt: 2026-08-06T11:13:41.996Z
---

You can send change approval events to external systems, such as issue tracking or continuous integration and continuous delivery (CI/CD) tools. Your team stays informed of approval activity without watching the Optimizely dashboard. A webhook fires when a change request is created, updated, or archived. Each event includes links back to Optimizely to review and act on the request.

For an overview of approval policies and the review workflow, see [Change approvals in Feature Experimentation](docId\:gSwTnrorRNUCPBrMVwBjt).

Webhooks are registered at the project level. A single webhook URL receives events for every environment in the project, so use the `environment` field in the payload to filter for the environments you care about.

## Configure a webhook

1. Go to **Settings** > **Webhooks**.
2. Add a webhook and enter the destination URL.
3. Select the change approval events to send.
4. Save the webhook.

When an event fires, use the payload links to act on the request. Follow the `ui_url` to review and act in Optimizely. Use the `api_url` to fetch the change request through the REST API, where you can also approve or reject it.

## Change approval events

A change approval webhook fires on three lifecycle events:

- `project.approval_created` – A user submits a change request for approval.
- `project.approval_updated` – The approval status changes to approved, rejected, or withdrawn.
- `project.approval_archived` – A resolved change request is archived.

## Webhook payload

The payload envelope carries the event type, project, and timestamp. The `data` array carries one entry per change request. The following example shows a `project.approval_updated` event:

```json
{
  "project_id": 1234567890123456,
  "timestamp": 1700000000,
  "event": "project.approval_updated",
  "data": [
    {
      "change_type": "update",
      "environment": "development",
      "summary": "Updated approval 'flag2'",
      "entity": {
        "type": "approval",
        "id": 33333,
        "name": "flag2",
        "api_url": "https://api.optimizely.com/v2/projects/1234567890123456/change_requests/33333",
        "ui_url": "https://app.optimizely.com/v2/projects/1234567890123456/flags/approvals"
      },
      "user": {
        "email": "user@example.com",
        "display_name": "user@example.com"
      },
      "changes": [
        {
          "property": "approval_status",
          "before": "pending",
          "after": "withdrawn"
        }
      ]
    }
  ]
}
```

These properties carry the most useful information:

- `event` – The lifecycle event that triggered the webhook.
- `environment` – The environment the change request belongs to. Use it to filter events.
- `entity.name` – The flag key the change request targets.
- `entity.ui_url` – A direct link to the approvals page in Optimizely.
- `entity.api_url` – A REST API URL to fetch the full change request.
- `summary` – A human-readable description of the change, safe to display.
- `user.email` – The user who performed the action.
- `changes` – An array of property-level diffs that describe what changed.

## Interpret the changes array

Each entry in `changes` records one property that changed, with `before` and `after` values. The `before` value is absent when a field is added. The `after` value is absent when a field is removed. Watch these properties:

- `approval_status` – The approval outcome. Values move from `pending` to `approved`, `rejected`, or `withdrawn`.
- `job_status` – The execution status of the underlying scheduled change. Values are `pending` (waiting), `canceled` (does not run), or `completed` (applied).
- `status_history.*` – Audit-trail entries. Each `after` value holds the actor email, status, reason, and timestamp.
- `operations` – The concrete edits applied to the flag if the approval is granted. This describes the content of the change, while `approval_status` describes the workflow.

The `operations` value is an array of JSON Patch operations ([RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902)). Each operation has an `op` (such as `add`, `remove`, or `replace`), a `path`, and a `value`. The `path` points into the flag or ruleset structure. A single approval can bundle several operations, so render them as a list.
