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

# Webhooks

> With Webhooks, you can receive real-time updates on connector sync statuses, as well as notifications whenever HRIS data is created or modified. This ensures you stay up-to-date with the latest changes and maintain accurate, synchronized information across your systems, enhancing your workflow efficiency and data reliability.

## Create Webhooks

To create webhooks follow the intructions up ahead!

**Step 1:** Navigate to the “Webhooks” section from the sidebar under the “Configure” menu.

![Webhook New](https://images.unifyx.dev/documentation_images/webhook_name.webp)

**Step 2:** In the “New webhook” section, enter the destination URL where you want to receive the webhook notifications in the “Destination URL” field.

![Webhook Create](https://images.unifyx.dev/documentation_images/webhook_create.webp)

**Step 3:** Optionally, click the “Test URL” button to ensure that your destination URL is correctly set up and can receive test data.

**Step 4:** Provide a meaningful name for your webhook in the “Webhook Name” field. For example, “Employee data.”

**Step 5:** Choose the events for which you want to receive notifications by selecting the appropriate checkboxes:

* **Sync start**: Receive an alert when a connector’s sync starts.
* **Sync error**: Get notified when a connector sync fails.
* **Sync completed**: Get notified when a connector sync job is successful.
* **Employee model change**: Receive an alert when any employee data is modified.
* **Data model change**: Receive an alert when any data model is modified.

**Step 6:** Once you have filled in all the required fields and selected the notification triggers, click the “Create webhook” button to save your webhook configuration.

## Payload Properties

* `hook`: The webhook that was triggered.
* `connector`: The connector whose data has changed.
* `data`: The affected data model.

## Webhook event types

* Connector Sync Started
* Connector Synced
* Connector Sync Error
* Employee Data Changed
* Connector Data Modified

### Sample payload for webhook events

<Tabs>
  <Tab title="Connector Sync Started">
    Recieve an alert when the connector sync starts

    ```json theme={null}
    {
        "webhook": {
            "webhook_id": "10c9a6b1-4ea8-476e-bdb0-193001a94a8d",
            "url": "https://webhook-test.com/8e771727c78e3a4017f374fb745313b6",
            "event": "connector_sync_started"
        },
        "connector": {
            "id": "018f99e2-ed3a-7f4c-ae97-83d619bdf95c",
            "display_name": "BreatheHR",
            "categories": [
            "HRIS"
            ],
            "org_name": "Test Org",
            "origin_id": "user_123",
            "connector_status": "COMPLETE",
            "end_user_name": "John Doe",
            "end_user_email": "abc@xyz.com"
        },
        "data": {
            "id": "018f99e7-886b-7c9f-a63a-f6fbc9da1f83",
            "integration_name": "breathehr",
            "initial_sync": true,
            "category": "HRIS",
            "display_status": "Syncing",
            "last_sync_start_time": "2024-07-22T09:49:30.478384+00:00"
        }
    }
    ```
  </Tab>

  <Tab title="Connector Synced">
    Recieve an alert when the connector sync finishes

    ```json theme={null}
    {
      "webhook": {
          "webhook_id": "10c9a6b1-4ea8-476e-bdb0-193001a94a8d",
          "url": "https://webhook-test.com/8e771727c78e3a4017f374fb745313b6",
          "event": "connector_synced"
      },
      "connector": {
          "id": "018f99e2-ed3a-7f4c-ae97-83d619bdf95c",
          "display_name": "BreatheHR",
          "categories": [
          "HRIS"
          ],
          "org_name": "Test Org",
          "origin_id": "user_123",
          "connector_status": "COMPLETE",
          "end_user_name": "John Doe",
          "end_user_email": "abc@xyz.com"
      },
      "data": {
          "id": "018f99e7-886b-7c9f-a63a-f6fbc9da1f83",
          "integration_name": "breathehr",
          "initial_sync": true,
          "category": "HRIS",
          "display_status": "Done",
          "last_sync_start_time": "2024-07-22T09:49:22.922083+00:00"
      }
    }
    ```
  </Tab>

  <Tab title="Connector Sync Error">
    Recieve an alert when the connector sync fails

    ```json theme={null}
    {
      "webhook": {
          "webhook_id": "10c9a6b1-4ea8-476e-bdb0-193001a94a8d",
          "url": "https://webhook-test.com/8e771727c78e3a4017f374fb745313b6",
          "event": "connector_sync_error"
      },
      "connector": {
          "id": "018f99e2-ed3a-7f4c-ae97-83d619bdf95c",
          "display_name": "BreatheHR",
          "categories": [
          "HRIS"
          ],
          "org_name": "Test Org",
          "origin_id": "user_123",
          "connector_status": "COMPLETE",
          "end_user_name": "John Doe",
          "end_user_email": "abc@xyz.com"
      },
      "data": {
          "id": "018f99e7-886b-7c9f-a63a-f6fbc9da1f83",
          "integration_name": "breathehr",
          "initial_sync": true,
          "category": "HRIS",
          "display_status": "Failed",
          "last_sync_start_time": "2024-07-22T07:03:49.967851+00:00"
      }
    }
    ```
  </Tab>

  <Tab title="Employee Data Changed">
    Recieve an alert when a employee is created or edited. It returns the `id` of the employees created or modified.

    ```json theme={null}
    {
      "webhook": {
          "webhook_id": "10c9a6b1-4ea8-476e-bdb0-193001a94a8d",
          "url": "https://webhook-test.com/8e771727c78e3a4017f374fb745313b6",
          "event": "employee_data_changed"
      },
      "connector": {
          "id": "018f99e2-ed3a-7f4c-ae97-83d619bdf95c",
          "display_name": "BreatheHR",
          "categories": [
          "HRIS"
          ],
          "org_name": "Test Org",
          "origin_id": "user_123",
          "connector_status": "COMPLETE",
          "end_user_name": "John Doe",
          "end_user_email": "abc@xyz.com"
      },
      "data": [
          "0190d9d8-ac9b-76cb-a5ee-df70994e6f3d"
      ]
    }
    ```
  </Tab>

  <Tab title="Connector Data Modified">
    Recieve an alert when any data model is created or edited. It returns the `id` of the data model created or modified.

    ```json theme={null}
    {
      "webhook": {
          "webhook_id": "10c9a6b1-4ea8-476e-bdb0-193001a94a8d",
          "url": "https://webhook-test.com/8e771727c78e3a4017f374fb745313b6",
          "event": "connector_data_modified"
      },
      "connector": {
          "id": "018f99e2-ed3a-7f4c-ae97-83d619bdf95c",
          "display_name": "BreatheHR",
          "categories": [
          "HRIS"
          ],
          "org_name": "Test Org",
          "origin_id": "user_123",
          "connector_status": "COMPLETE",
          "end_user_name": "John Doe",
          "end_user_email": "abc@xyz.com"
      },
      "data": {
          "hris_bank_info": [
          "0190d9d8-cf5b-7ce4-b60f-1fd95c04adee"
          ],
          "hris_employment": [
          "0190d9d9-023d-7259-97e1-b38682dec062"
          ]
      }
    }
    ```
  </Tab>
</Tabs>

## Security

To secure your API endpoint, ensure it verifies that POST requests are genuinely from Bindbee and not from a malicious source, and that payloads haven’t been tampered with during transit.

You can achieve this by checking if the `X-Bindbee-Webhook-Signature` field in the request header matches an encoded combination of your organization’s unique webhook signature and the payload of the incoming request.

In the Webhooks configuration page, you should find a Security section where you can access your signature key. This key is unique to your organization and can be regenerated if it becomes known to an unauthorized party.

![Webhook Security](https://images.unifyx.dev/documentation_images/signature_key.webp)

<CodeGroup>
  ```python Python theme={null}
  import base64
  import hashlib
  import hmac
   
  # Replace 'YOUR_WEBHOOK_SIGNATURE_KEY' with the actual key from:
  # https://app.bindbee.dev/webhooks
   
  signature_key = "YOUR_WEBHOOK_SIGNATURE_KEY"
  request_body = request.body
   
  # Ensure the presence of a signature header in the request
  if "X-Bindbee-Webhook-Signature" not in request.headers:
      print('Signature header missing; request may not be from Bindbee.')
      raise
   
  # Retrieve the signature header from the request
  received_signature = request.headers["X-Bindbee-Webhook-Signature"]
   
  # Convert the key and request body to bytes
  key_bytes = signature_key.encode("utf-8")
  body_bytes = request_body.encode("utf-8")
   
  # Create an HMAC digest using SHA-256
  hmac_digest = hmac.new(key_bytes, body_bytes, hashlib.sha256).digest()
   
  # Encode the digest to base64
  encoded_digest = base64.urlsafe_b64encode(hmac_digest).decode()
   
  # Use `hmac.compare_digest` to compare the computed digest with the received signature
  signature_valid = hmac.compare_digest(encoded_digest, received_signature)
  ```

  ```ruby Ruby theme={null}
  require 'base64'
  require 'openssl'
  require 'json'
   
  # Replace 'YOUR_WEBHOOK_SIGNATURE_KEY' with the actual key from:
  # https://app.bindbee.dev/webhooks
   
  secret_key = 'YOUR_WEBHOOK_SIGNATURE_KEY'
  request_body = request.raw_post
  received_signature = request.env['X-Bindbee-Webhook-Signature']
   
  unless received_signature
    raise "Signature header missing; request may not be from Bindbee."
  end
   
  # Ensure the payload is properly encoded in UTF-8
  request_body.force_encoding('UTF-8')
   
  # Compute HMAC digest using SHA-256
  hmac_digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret_key, request_body)
   
  # Base64 encode the HMAC digest
  encoded_digest = Base64.urlsafe_encode64(hmac_digest)
   
  # Use secure comparison to validate the signature
  valid_signature = ActiveSupport::SecurityUtils.secure_compare(encoded_digest, received_signature)
  ```

  ```javascript Node theme={null}
  const crypto = require('crypto');
  const express = require('express');
  const app = express();
   
  // Replace 'YOUR_WEBHOOK_SIGNATURE_KEY' with the actual key from:
  // https://app.bindbee.dev/webhooks
   
  // Middleware to capture raw body for HMAC verification
  app.use(
    express.json({
      verify: (req, res, buf) => {
        req.rawBody = buf.toString();
      }
    })
  );
   
  const webhookSecret = 'YOUR_WEBHOOK_SIGNATURE_KEY';
  const rawRequestBody = request.rawBody;
   
  const receivedSignature = request.headers['X-Bindbee-Webhook-Signature'];
   
  if (!receivedSignature) {
    console.log('Missing webhook signature; request may not be from Bindbee.');
  }
   
  // Ensure the request body is properly encoded
  const utf8Body = Buffer.from(rawRequestBody, 'utf-8').toString();
   
  // Create an HMAC digest using SHA-256
  const hmacDigest = crypto.createHmac('sha256', webhookSecret)
    .update(utf8Body)
    .digest('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');
   
  // Use crypto.timingSafeEqual to compare the signatures securely
  const expectedSignature = Buffer.from(receivedSignature, 'utf-8');
  const calculatedSignature = Buffer.from(hmacDigest, 'utf-8');
   
  const isSignatureValid = Buffer.byteLength(expectedSignature) === Buffer.byteLength(calculatedSignature) &&
    crypto.timingSafeEqual(expectedSignature, calculatedSignature);
   
  console.log(isSignatureValid);
  ```
</CodeGroup>

## Webhook Visibility

The webhook logs are easily visible on the webhooks tab at [Bindbee](https://app.bindbee.dev/logs/webhooks) dashboard.
The specific webhook logs will be visible on the individual webhook page.
