Webhooks
Webhooks let your integrations take action in response to events that occur in Eppo.
Experiment Webhook Events
This webhook is a good solution when a custom application needs to display or take action on the most up to date state of an experiment.
The webhook sends four types of experiment update events. If you only want to take action based on certain types of events, you can filter to just the events you are interested in subscribing to based on their event type in the request body.
Experiment Metric Updated
Triggers when:
- Metric is added or removed
- Metric collection is added or removed
Request body:
{
"event": "experiment.metric.updated",
"data": {
"experiment_id": "<experiment_id>",
"experiment_key": "<experiment_key>"
},
"signature": "<signature>"
}
Experiment Configuration Updated
Triggers when:
- User edits any configuration
Request body:
{
"event": "experiment.configuration.updated",
"data": {
"experiment_id": "<experiment_id>",
"experiment_key": "<experiment_key>"
},
"signature": "<signature>"
}
Experiment Status Updated
Triggers when:
- Experiment's status changes
Request body:
{
"event": "experiment.status.updated",
"data": {
"experiment_id": "<experiment_id>",
"experiment_key": "<experiment_key>"
},
"signature": "<signature>"
}
Experiment Calculated Metrics Updated
Triggers when:
- Data pipeline run irrespective of success or failure and mode of trigger manual or scheduled
Request body:
{
"event": "experiment.calculated_metrics.updated",
"data": {
"experiment_id": "<experiment_id>",
"experiment_key": "<experiment_key>",
"meta_data": {
"status": "<success | failure>",
"is_manual_refresh": "<boolean>",
"is_data_updated": "<boolean>",
"time_taken_seconds": "<number>",
"is_traffic_imbalance": "<boolean>",
"assignments_scan_start_date": "<date>",
"assignments_scan_end_date": "<date>"
}
},
"signature": "<signature>"
}
Flagging Webhooks
The flagging webhook is a good solution when a custom application needs to display or take action on the most up to date state of a flag.
Flag Configuration Updated
This webhook is sent when a flag or its associated models, such as assignments, targeting rules, environments or audiences, are updated.
In short, any operation visible in the Flag History is sent to the webhook.
Request body:
{
"event": "flag.configuration.updated",
"data": {
"flag": {
"id": "<flag_id>",
"key": "<flag_key>"
}
},
"signature": "<signature>"
}
Configuring the webhook
To use the webhook, you first need to setup a URL on your side to receive the webhook payload.
The configuration is done in the Admin > Integrations page.
Once that is done, contact Eppo support to customize the webhook to your needs.
Webhook Signature
The webhook payload is signed with a signature. The signature is a hash of the payload and the webhook secret.
Integrating and Verifying the Signature
To verify the webhook signature, you'll need to:
- Get the signature from the webhook payload
- Generate a HMAC SHA-256 hash of the raw request body using your webhook secret
- Compare the generated hash with the received signature
Here's an example in TypeScript/Node.js:
import crypto from 'crypto';
function generateHMACSignature(secret: string, payload: string): string {
return crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
}
function isValidWebhookSignature(
payload: string,
signature: string,
webhookSecret: string
): boolean {
const expectedSignature = generateHMACSignature(webhookSecret, payload);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Example usage in an Express route handler
app.post('/webhook', (req, res) => {
const signature = req.body.signature;
const payload = JSON.stringify(req.body);
const webhookSecret = process.env.WEBHOOK_SECRET;
if (!isValidWebhookSignature(payload, signature, webhookSecret)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook
// ...
});
Always use a constant-time comparison function (like crypto.timingSafeEqual
) when comparing signatures to prevent timing attacks.