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

# Verify Webhook Events Are From Dojah

> Confirm webhook payloads are authentic. Use IP whitelisting or signature validation so only Dojah can trigger your endpoint.

1. IP Whitelisting.
2. Signature validation with secret and payload (x-dojah-signature).
3. Signature validation with secret only (x-dojah-signature-v2).

## [](https://docs.dojah.io/docs/subscribe-to-services#ip-whitelisting)

## IP Whitelisting.

With this method, you only allow certain IP addresses to access your webhook URL while blocking out others. Dojah will only send webhooks from these IP addresses:

**135.119.89.106**

## [](https://docs.dojah.io/docs/subscribe-to-services#signature-validation)

## Signature validation with secret and payload.

Events sent from Dojah carry the **x-dojah-signature** header. The value of this header is a HMAC SHA256 signature of the event payload signed using your secret key. Verifying the header signature should be done before processing the event:

<CodeGroup>
  ```javascript JavaScript theme={null}
  var crypto = require('crypto');
  var secret = process.env.SECRET_KEY;

  // Using Express
  app.post("/webhookurl", function(req, res) {
      //validate event
      const hash = crypto.createHmac('sha256', secret).update(JSON.stringify(req.body)).digest('hex');

      if (hash == req.headers['x-dojah-signature']) {
      // Retrieve the request's body
      const event = req.body;
      // Do something with event  
      }
      res.send(200);
  });
  ```

  ```python Python theme={null}
  import hmac
  import hashlib
  import os
  from flask import Flask, request

  app = Flask(__name__)
  secret = os.environ["SECRET_KEY"]

  @app.route("/webhookurl", methods=["POST"])
  def webhook():
      payload = request.get_data()
      hash_value = hmac.new(
          secret.encode("utf-8"),
          payload,
          hashlib.sha256
      ).hexdigest()

      if hash_value == request.headers.get("x-dojah-signature"):
          event = request.get_json()
          # Do something with event

      return "", 200
  ```

  ```go Go theme={null}
  package main

  import (
  	"crypto/hmac"
  	"crypto/sha256"
  	"encoding/hex"
  	"io"
  	"net/http"
  	"os"
  )

  func webhookHandler(w http.ResponseWriter, r *http.Request) {
  	secret := os.Getenv("SECRET_KEY")
  	body, _ := io.ReadAll(r.Body)
  	defer r.Body.Close()

  	mac := hmac.New(sha256.New, []byte(secret))
  	mac.Write(body)
  	hash := hex.EncodeToString(mac.Sum(nil))

  	if hash == r.Header.Get("x-dojah-signature") {
  		// Do something with event
  	}

  	w.WriteHeader(200)
  }

  func main() {
  	http.HandleFunc("/webhookurl", webhookHandler)
  	http.ListenAndServe(":3000", nil)
  }
  ```

  ```ruby Ruby theme={null}
  require "sinatra"
  require "json"
  require "openssl"

  secret = ENV["SECRET_KEY"]

  post "/webhookurl" do
    payload = request.body.read
    hash = OpenSSL::HMAC.hexdigest("sha256", secret, payload)

    if hash == request.env["HTTP_X_DOJAH_SIGNATURE"]
      event = JSON.parse(payload)
      # Do something with event
    end

    status 200
  end
  ```

  ```php PHP theme={null}
  <?php
  $secret = getenv('SECRET_KEY');
  $payload = file_get_contents('php://input');
  $hash = hash_hmac('sha256', $payload, $secret);

  if ($hash === $_SERVER['HTTP_X_DOJAH_SIGNATURE']) {
      $event = json_decode($payload, true);
      // Do something with event
  }

  http_response_code(200);
  ```
</CodeGroup>

## Signature validation with secret only.

Events sent from Dojah carry the **x-dojah-signature-v2** header. The value of this header is a HMAC SHA256 signature of your secret key. Verifying the header signature should be done before processing the event:

<CodeGroup>
  ```javascript JavaScript theme={null}
  var crypto = require('crypto');
  var secret = process.env.SECRET_KEY;
  const encoder = new TextEncoder();

  // Using Express
  app.post("/webhookurl", async function(req, res) {
         
         //validate event

          const data = encoder.encode(secret);
          const hashBuffer = await crypto.subtle.digest('SHA-256', data);
          const hashArray = Array.from(new Uint8Array(hashBuffer));
          const hash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');

      if (hash == req.headers['x-dojah-signature-v2']) {
      
      // i.e the hash generated matches with the header signature


      }
      res.send(200);
  });
  ```

  ```python Python theme={null}
  import hashlib
  import os
  from flask import Flask, request

  app = Flask(__name__)
  secret = os.environ["SECRET_KEY"]

  @app.route("/webhookurl", methods=["POST"])
  def webhook():
      hash_value = hashlib.sha256(secret.encode("utf-8")).hexdigest()

      if hash_value == request.headers.get("x-dojah-signature-v2"):
          event = request.get_json()
          # Do something with event

      return "", 200
  ```

  ```go Go theme={null}
  package main

  import (
  	"crypto/sha256"
  	"encoding/hex"
  	"net/http"
  	"os"
  )

  func webhookHandler(w http.ResponseWriter, r *http.Request) {
  	secret := os.Getenv("SECRET_KEY")
  	h := sha256.Sum256([]byte(secret))
  	hash := hex.EncodeToString(h[:])

  	if hash == r.Header.Get("x-dojah-signature-v2") {
  		// Do something with event
  	}

  	w.WriteHeader(200)
  }

  func main() {
  	http.HandleFunc("/webhookurl", webhookHandler)
  	http.ListenAndServe(":3000", nil)
  }
  ```

  ```ruby Ruby theme={null}
  require "sinatra"
  require "json"
  require "digest"

  secret = ENV["SECRET_KEY"]

  post "/webhookurl" do
    hash = Digest::SHA256.hexdigest(secret)

    if hash == request.env["HTTP_X_DOJAH_SIGNATURE_V2"]
      event = JSON.parse(request.body.read)
      # Do something with event
    end

    status 200
  end
  ```

  ```php PHP theme={null}
  <?php
  $secret = getenv('SECRET_KEY');
  $hash = hash('sha256', $secret);

  if ($hash === $_SERVER['HTTP_X_DOJAH_SIGNATURE_V2']) {
      $payload = file_get_contents('php://input');
      $event = json_decode($payload, true);
      // Do something with event
  }

  http_response_code(200);
  ```
</CodeGroup>
