> ## Documentation Index
> Fetch the complete documentation index at: https://docs.promptlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Use webhooks to receive notifications about prompt, dataset, evaluation, workflow, and skill collection events in your workspace.

<a id="webhooks" />

PromptLayer webhooks let your systems react to workspace changes so you can keep prompt caches fresh, trigger CI/CD or GitOps workflows, sync external systems, and monitor asynchronous jobs without polling.

For event names and payload details, see [Events](/features/prompt-registry/webhook-events).

### Configuring a Webhook

To set up a webhook, go to the **Webhook** section in the **Settings** page. Enter the URL of the endpoint you want to send the webhook to and click **Submit**.

<img src="https://mintcdn.com/promptlayer/v0RzaTvbzopITX7U/images/webhooks-form.png?fit=max&auto=format&n=v0RzaTvbzopITX7U&q=85&s=9fcbc2bbe5af10959ee4fffd9baa4249" alt="Creating Webhook" width="1166" height="472" data-path="images/webhooks-form.png" />

### Securing Your Webhook

When you create a webhook, you'll receive a webhook secret signature that looks like this:

<img src="https://mintcdn.com/promptlayer/v0RzaTvbzopITX7U/images/webhook-secret-signature.png?fit=max&auto=format&n=v0RzaTvbzopITX7U&q=85&s=9d2095002aa831c5352e372ade4f5d05" alt="Webhook Secret Signature" width="1732" height="1272" data-path="images/webhook-secret-signature.png" />

This secret is used to verify that incoming webhook requests are authentic and come from PromptLayer. The signature is included in the `X-PromptLayer-Signature` header of each webhook request.

#### Verifying Webhook Signatures

Here are code examples showing how to verify the signatures:

<CodeGroup>
  ```python Python theme={null}

  import hmac
  import hashlib
  import json

  signature = "HEADER FROM X-PromptLayer-Signature" # Replace with actual header value
  secret_key = "SECRET KEY FROM PROMPTLAYER DASHBOARD" # Replace with actual secret key
  payload = {} # Replace with actual payload
  payload_str = json.dumps(payload, sort_keys=True)
  expected_signature = hmac.new(
      key=secret_key.encode(),
      msg=payload_str.encode('utf-8'),
      digestmod=hashlib.sha256
  ).hexdigest()

  if hmac.compare_digest(expected_signature, signature):
      print("Signature is valid")
  else:
      print("Signature is invalid")
  ```

  ```javascript JavaScript theme={null}
  import crypto from "crypto";
  import stringify from "json-stable-stringify";

  // Replace these with actual values
  const signature = "HEADER FROM X-PromptLayer-Signature"; // From request header
  const secretKey = "SECRET KEY FROM PROMPTLAYER DASHBOARD"; // Your webhook secret
  const payload = {}; // Replace with actual request body

  export function formatPayload(payload) {
    const raw = stringify(payload);
    const spacedColons = raw.replace(/"([^"]+)"\s*:/g, '"$1": ');
    const spaced = spacedColons.replace(/,(?=(?:\s*[\{"\[]))/g, ", ");
    return spaced;
  }

  export function generateSignature(payload, secretKey) {
    const normalized = formatPayload(payload);
    return crypto
      .createHmac("sha256", secretKey)
      .update(normalized)
      .digest("hex");
  }

  export function verifySignature(signature, payload, secretKey) {
    const expected = generateSignature(payload, secretKey);
    try {
      return crypto.timingSafeEqual(
        Buffer.from(signature, "hex"),
        Buffer.from(expected, "hex")
      );
    } catch {
      return false;
    }
  }
   
  const isValid = verifySignature(signature, payload, secretKey);
  console.log("Signature is", isValid ? "valid" : "invalid");
  ```
</CodeGroup>
