Webhook Use Case

Use our webhooks to be notified about finished syncs. This allows you to fetch any changes that occurred during a sync and to keep your database up to date without scheduling/polling. Easily test webhooks with Webhook.site.

Enable Webhooks

You can configure your Kombo webhooks in the dashboard directly in the webhooks tab. After creating the first webhook, a random webhook secret will be generated and shown. You can learn how to use it in Validate the data.

1412

Available webhooks

Sync finished

The sync-finished webhook is sent every time a sync finishes, regardless of the sync state. Possible values for sync_state are:

  • SUCCEEDED The sync finished successfully.
  • FAILED There was a critical error during the sync and the sync did not finish.
  • PARTIALLY_FAILED There was a non-critical error that needs your attention. Please check the logs for actionable error messages or contact us for support.
  • AUTHENTICATION_FAILED The authentication of the connection is incorrect. Please check the Kombo dashboard for further steps.
sync-finished
{
  "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
  "type": "sync-finished",
  "data": {
    "sync_id": "B89SCXXho7Yw8PGo8AKJxLn4",
    "sync_state": "SUCCEEDED",
    "sync_started_at": "2021-09-01T12:00:00.000Z",
    "sync_ended_at": "2021-09-01T12:30:00.000Z",
    "sync_duration_seconds": 1800,
    "integration_id": "personio:CBNMt7dSNCzBdnRTx87dev4E",
    "integration_tool": "personio",
    "integration_category": "HRIS",
    "end_user": {
      "origin_id": "36123",
      "creator_email": "user@example.com",
      "organization_name": "Acme, Inc."
    },
    "log_url": "https://app.kombo.dev/env/production/logs/C3xUo6XAsB2sbKC7M1gyXaRX"
  }
}

Integration created

The integration-created webhook is sent for every integration that is created. Please react to this webhook event by adding the integration to your database or by performing any other business logic that is required when an integration is created.

integration-created
{
  "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
  "type": "integration-created",
  "data": {
    "id": "personio:CBNMt7dSNCzBdnRTx87dev4E",
    "tool": "personio",
    "category": "HRIS",
    "end_user": {
      "origin_id": "36123",
      "creator_email": "user@example.com",
      "organization_name": "Acme, Inc."
    }
  }
}

Integration deleted

The integration-deleted webhook is sent when an integration is deleted. Please react to this webhook event by removing the integration from your database or by performing any other business logic that is required when an integration is deleted.

integration-deleted
{
  "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
  "type": "integration-deleted",
  "data": {
    "id": "personio:CBNMt7dSNCzBdnRTx87dev4E",
    "tool": "personio",
    "category": "HRIS",
    "end_user": {
      "origin_id": "36123",
      "creator_email": "user@example.com",
      "organization_name": "Acme, Inc."
    },
    "deleted_at": "2022-11-02T10:50:10.242Z"
  }
}

Connection flow failed

The connection-flow-failed webhook is sent whenever an error occurs during the connection flow. These errors could, for example, originate from a user entering incorrect credentials or from a mismatch between the required and supplied API permissions.

This is not an alert-type webhook, but should instead be used to collect data and get insights into user behavior. The connection flow can still be successfully completed after this webhook is sent.

You can check whether the connection flow ended successfully by following the link under log_url. Additionally, the log will display the exact errors your customer ran into, which you can use to provide support if needed.

connection-flow-failed
{
  "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
  "type": "connection-flow-failed",
  "data": {
    "integration_tool": "personio",
    "integration_category": "HRIS",
    "end_user": {
      "origin_id": "36123",
      "creator_email": "user@example.com",
      "organization_name": "Acme, Inc."
    },
    "log_url": "https://app.kombo.dev/env/production/logs/C3xUo6XAsB2sbKC7M1gyXaRX"
  }
}

Assessment order received

The assessment:order-received webhook is sent every time an assessment is ordered for a candidate from within an end-customer’s tool.

assessment:order-received
{
  "id": "HAQ9uCfC1zi3TLbB1n5cyHgP",
  "type": "assessment:order-received",
  "data": {
    "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
    "package_id": "typescript_test",
    "status": "OPEN",
    "integration_id": "workday:CBNMt7dSNCzBdnRTx87dev4E",
    "candidate": {
      "email": "john.doe@gmail.com",
      "first_name": "John",
      "last_name": "Doe",
      "phone": "+1 123 456 7890",
      "remote_id": null
    }
  }
}

Integration state changed

The integration-state-changed webhook is sent when the status of the integration changes. Use this to detect stale credentials and to reconnect your customer.

Possible values for the "state" key include:

  • ACTIVE The integration is active and working.
  • INVALID The connection requires reconnection in order to work again.
  • INACTIVE Upon your request, Kombo support can mark the integration as inactive.
integration-state-changed
{
  "id": "5gjAtURLPbnTiwgkaBfiA3WJ",
  "type": "integration-state-changed",
  "data": {
    "integration_tool": "personio",
    "integration_category": "HRIS",
    "integration_id": "personio:CBNMt7dSNCzBdnRTx87dev4E",
    "end_user": {
      "origin_id": "36123",
      "creator_email": "user@example.com",
      "organization_name": "Acme, Inc."
    },
    "qa_status": "PASSED",
    "state": "ACTIVE",
    "updated_at": "2021-09-01T12:00:00.000Z"
  }
}

Validate the data

Anyone could post data to your webhook URL. That’s why we’re signing each request with a secret specific to your Kombo account. The secret is called Kombo Webhook Secret will be sent to you when we activate Webhooks for you.

Each valid webhook POST from us will include the X-Kombo-Signature header. Validate it by:

  1. Using HMAC-SHA256 to sign the request body with your Kombo Webhook Secret
  2. Digest with base64url encoding.

Our ‘base64url’ encoding does not include the optional trailing ’=’ padding characters.

Here are some examples of how you could achieve this in a few different languages:

import { createHmac } from 'node:crypto'

const signatureHeader = req.headers['x-kombo-signature']

// Get the raw UTF-8-encoded string body because this was used for signing
const body = request.body

// Or if you use a framework that parses the body for you, you can use this.
// Note: This is not the same as JSON.stringify(request.body)
const body = JSON.stringify(request.body, null, 2)

const signature = createHmac('sha256', KOMBO_WEBHOOK_SECRET)
.update(body, 'utf8')
.digest('base64url')

const isValidRequest = signature === signatureHeader

You have to use exactly the same string we use for signing. This means that you should optimally use the raw body. Alternatively, you can manually turn the parsed body into a string again. In that case, make sure to use the exact same encoding and indentation (e.g., JSON.stringify(body, null, 2) in JavaScript).

Testing webhooks

The list of all created webhooks has two buttons on the right. One is for deleting the webhook, the other is for sending a test request. This test request will contain dummy data but will use the correct data schema.

Be careful when using this feature in production! It will send invalid data to your webhook.

Testing locally

For local development, you can use a service like localtunnel or ngrok. These tools allow you to expose a local port through a public URL provided by them. The setup is very straightforward: Once you’ve started a tunnel, simply add the provided URL as a webhook in the Kombo dashboard. You can then send test requests to validate that your endpoint is working properly.