Title: General-purpose webhook URLs
Author: WordPress VIP Documentation
Published: August 2, 2023
Last modified: August 6, 2024

---

 1. [Notifications](https://docs.wpvip.com/notifications/)
 2. [Destinations](https://docs.wpvip.com/notifications/destinations/)
 3. General-purpose webhook URLs

#  General-purpose webhook URLs

A general-purpose webhook URL can be configured for the [Destinations of organization and application Notifications](https://docs.wpvip.com/notifications/destinations/)
and [Important Alerts](https://docs.wpvip.com/notifications/important-alerts/).

Notifications pings to a webhook URL can be useful for:

 * Pinging a testing service whenever a particular environment is updated. This 
   can include page speed tests or integration testing to ensure that a checkout
   process is still working as expected.
 * Logging the deployment against a datastore (e.g. a Google spreadsheet).

## Request header and versions

The webhook request is sent with an `x-wpvip-webhook` HTTP request header. The `
x-wpvip-webhook` header value is a string indicating the version number of the webhook
payload.

When breaking changes are made to the payload structure the version number will 
be incremented.

 * Current webhook version: `v1` (e.g. `x-wpvip-webhook: "v1"`)
 * Legacy webhook version: `v0` (e.g. `x-wpvip-webhook: "v0"`)

## Request body

The service receiving the Notifications ping must be able to accept an HTTP `POST`.
The ping sent by Notifications is a JSON-formatted request body.

Example request body structure for an event related to a single environment:

    ```lang-json
    {
      "type": "environment:code:deployed",
      "timestamp": "2024-01-26T22:16:30.000Z",
      "data": {
        "application": {
          "id": 8886,
          "name": "example-app"
        },
        "branch": "develop",
        "commit": {
          "author": "example-user",
          "description": "Example commit message",
          "hash": "0abc1234e5af99deadbeefb98765432181e03b1a5b5d69"
        },
        "deploymentId": 12345678,
        "environment": {
          "domain": "develop.example.com",
          "id": 5678,
          "type": "develop"
        },
        "repo": "wpcomvip/example-app"
      }
    }
    ```

Example request body structure for an event related to more than one environment:

    ```lang-json
    {
      "data": {
        "environments": [
          {
            "appId": 8886,
            "appName": "example-app",
            "envName": "production"
          },
          {
            "appId": 8886,
            "appName": "example-app",
            "envName": "staging"
          }
        ],
        "organization": {
          "id": 123,
          "name": "My Org"
        },
        "severity": "CRITICAL",
        "severityScore": "7.4",
        "vulnerabilityId": "abc6def4-abab-4545-9bd0-2222eeeecccc",
        "vulnerabilityTitle": "ExamplePlugin < 1.2.7 - Authenticated(Contributor+) Stored Cross-Site Scripting via Shortcode"
      },
      "timestamp": "2024-07-11T18:59:48.000Z",
      "type": "organization:code:vulnerability-found"
    }
    ```

**Note**

Very infrequently, an environment might have a `name` value assigned to it in addition
to a `type` (e.g. “develop.01” where “develop” is the `type` value and “01” is the`
name` value). For these environments, both the `type` and the `name` keys and values
will be included in the payload.

## Event types

The `type` payload property contains a string that indicates the kind of event that
occurred. The behavior of the request handler can vary depending on the event type.

Currently supported event types:

 * `environment:code:deployed`
 * `environment:code:deploy-failed`
 * `environment:code:vulnerability-found`
 * `organization:code:vulnerability-found`

## Request verification

Outbound [webhook Notifications](https://docs.wpvip.com/notifications/) sent to 
endpoints configured by customers can be identified by the VIP User-Agent `VIP Webhooks(
+[https://docs.wpvip.com/vip-user-agents](https://docs.wpvip.com/vip-user-agents))`.
The presence of this User-Agent is a useful reference for identifying the source
of a request, but it should not be considered authoritative proof. Customers can
optionally configure more reliable verification methods for the source of Notifications
that are sent to webhook URLs.

### Shared secret

When configuring a webhook URL for a Destination, a unique parameter string can 
be added to the URL for verification purposes. The unique parameter string can then
be used as a “shared secret” by code on the receiving end to verify that the webhook
came from WordPress VIP.

A unique parameter string can be generated in many ways, but [`openssl` is a useful library](https://www.openssl.org/)
for generating unique, high-entropy strings for shared secrets.

In a webhook handler on the receiving end, a timing-safe comparison can be used 
to verify that the `secret` parameter that was sent in the webhook matches the expected
value.

This example demonstrates a version of this type of verification in PHP:

 1. Generate a string to be used as a shared secret with the command:

    ```wp-block-preformatted
    openssl rand -hex 24
    ```

 2. Copy the output and add it to a webhook URL as the value of a `?secret` query parameter.
    For example:

    ```wp-block-preformatted
    https://example.com/webhooks/wpvip?secret=a18b504dcc1a8ff2e476d93829f33
    ```

 3. [Create an environment variable with VIP-CLI](https://docs.wpvip.com/infrastructure/environments/manage-environment-variables/)
    and set the shared secret string as its value. For this example, the environment
    variable is created with the name `WEBHOOK_SECRET`.
 4. In a webhook handler on the receiving end, use a timing-safe comparison to verify
    that the `secret` parameter that was sent in the webhook matches the expected value
    of the environment variable.

    ```lang-php
    <?php

    ...

    $passed_secret = $_GET['secret'] ?? null;

    if ( ! hash_equals( $passed_secret, WEBHOOK_SECRET ) ) {
    	wp_die( 'Invalid webhook' );
    }

    // Secret verified, handle webhook
    ...
    ```

### IP address

WordPress VIP can also be verified as the sender of a webhook by IP address. Webhooks
sent from WordPress VIP will always come from an IP address that belongs to the 
[WordPress VIP Platform IP ranges](https://go-vip.net/ip-ranges.json).

Last updated: August 06, 2024