> ## Documentation Index
> Fetch the complete documentation index at: https://extend-eb-casing.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

## Setting up a webhook

To set up a webhook, you can create one in the Extend dashboard settings under the "Developer" tab

![](https://mintlify.s3-us-west-1.amazonaws.com/extend-eb-casing/images/webhooks/webhooks_add.png)

Once created, you will start to receive webhook events to the url you specified during workflow runs.

## Verifying webhook requests from Extend

Extend will sign each webhook request using a secret unique to the webhook. You can use this signature along with the timestamp to verify that the request is coming from Extend as well as protect against replay attacks.

### Steps to verify a webhook request from Extend

At a high level, the steps to verify a webhook request from Extend are

1. Retrieve the timestamp of the request from `x-extend-request-timestamp`, the body of the request, and the signing secret associated with the webhook.
2. Concatentate the timestamp and request body using the following format:
   `v0:${timestamp}:${requestBody}`
3. Compute a HMAC 256 digest on the resulting string using the signing secret as the key. The secret can be found in the webhooks table under the "Developer" tab

![](https://mintlify.s3-us-west-1.amazonaws.com/extend-eb-casing/images/webhooks/webhooks_secret.png)
4\. Compare this digest with the signature provided in `x-extend-request-signature`. If they are equal, then the request is verified to be from Extend.

Here is pseudocode in Javascript to perform the verification:

```typescript
  import crypto from "crypto";

  // retrieve from x-extend-request-timestamp
  const timestamp = 1707777128;

  const requestBodyString = JSON.stringify(request.body);

  // retrieve from the webhook details on the "Developers" tab
  const signingSecret = "wss_C...l";

  const message = `v0:${timestamp}:${requestBodyString}`;
  const expectedSignature = crypto.createHmac("sha256", signingSecret).update(message).digest("hex");

  // retrieve from x-extend-request-signature
  const receivedSignature = "d3a8d5de6d463023b052ee1eb8e7f247dce6bf90b4a3e1117b4922afdc90029b";

  if (expectedSignature === receivedSignature) {
    // proceed
  }
```

## Webhook event shape

| Field     | Description                                                                                                                               |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| eventId   | **string** - Unique identifier for the event                                                                                              |
| eventType | **string** - Type of the event that occurred (workflow\_run.completed)                                                                    |
| payload   | **object** - Contains the WorkflowRun object. See the [GET WorkflowRun endpoint](/api-reference/endpoint/get_workflow_run) for the shape. |

Here is what you can expect for a given incoming event:

```json Example Event
{
  "eventId": "event_1234",
  "eventType": "workflow_run.completed",
  "payload": {
    "object": "workflow_run",
    "id": "workflow_run_1234"
    // etc.
  }
}
```

## Event types

The following table outlines the various event types you can receive via webhooks:

| Event Type                  | Description                                     |
| --------------------------- | ----------------------------------------------- |
| workflow\_run.completed     | Triggered whenever a WorkflowRun is completed   |
| workflow\_run.failed        | Triggered whenever a WorkflowRun fails          |
| workflow\_run.needs\_review | Triggered whenever a WorkflowRun needs review\* |

\* Only triggered when the workflow is configured to have a HumanReview step in the Extend workflow builder.
