To allow the integration of Expel data without API polling, Expel can send webhook requests to external servers.
Webhook data model
The webhook body is UTF-8-encoded JSON.
The webhook json itself is a wrapper around a "change event", which is a structure that provides all the contextual data around an event within Workbench. This object varies by event but embeds a consistent series of representational Expel objects, for example, Investigation
and RemediationAction
.
-
guid
: the unique ID for the main object associated with the webhook. -
rule
: the name of the notification rule subscription that produced the webhook. -
event_name
: the name of the event that triggered the rule. This name maps directly to the "change event" object provided in thedata
key. -
data
: JSON model of the "change event" emitted by Workbench
{ "guid": "1a9c6d7a-78e6-4238-8cd7-8d2ec2492cab", "rule": "incident is created", "event_name": "incident_created", "data": {...} }
Webhook signature
Every webhook sent by Expel contains the HTTP header Expel-Signature-256
, formatted as sha256={some hash}
. The header is a SHA-256 HMAC of the webhook payload bytes, generated using a secret key. The secret key is provided through Workbench when the webhook integration is created. See Adding a webhook integration.
Example Python snippet showing signature header verification
import hmac import hashlib # secret_bytes, accessible by this verification secret # request object sent by Expel has been processed, with the body_bytes and header extracted # body_bytes # signature_header # extract the signature header_split = siganture_header.split("=") if len(header_split) < 2: # not a valid signature header return expel_sig = header_split[1] # generate an hmac of the body_bytes local_sig = hmac.new(secret_bytes, body_bytes, digestmod=hashlib.sha256).hexdigest() # constant time compare, returns a boolean valid_webhook = hmac.compare_digest(expel_sig, local_sig)
Note
All webhook requests that Expel send are encoded using UTF-8.
Webhook POST behavior
The receiving server is expected to reply with a status code to the webhook request. No response body is required.
-
200
: the request has been successfully received, no retries. -
406
: the server is actively rejecting the webhook, no retries. -
Any other valid
4xx
or5xx
code: indicates some failure on the server side in processing. The webhook request is resent up to 3 times with a backoff. -
Additionally, any connection failure also results in 3 retries.
Adding a webhook integration
To subscribe to webhook notifications in Workbench, you need to add at least one webhook integration.
-
From the main menu, click Organization Settings > Integrations.
-
At the bottom of the page, click Add a webhook destination.
-
Enter a name for the webhook.
-
Enter the destination URL to send the webhook requests to.
-
Copy the secret key for the webhook and save it in a safe location.
Caution
When you finish the process and click Add, you can't access this secret key again.
-
Click Add.
Adding a notification rule with a webhook destination
If at least one webhook integration exists, you can subscribe to notification rules where the destination is a webhook URL.
Best practices for securing webhooks
When setting up an HTTP server for consuming Expel webhooks, use the following best practices:
-
Ensure that the server always uses HTTPS and has a valid signed certificate.
-
Always verify the Expel-Signature-256 header sent with all valid requests.
-
Set a limit on requests per second and request size to prevent DOS.
It is unlikely that Expel webhooks will constitute a large volume of requests, but the server should be able to handle burst of requests.
-
Optionally, allowlist Expel's IP addresses to further limit unwanted traffic.