Outgoing webhooks
Push change events to any external system via signed HTTP POST requests.
Outgoing webhooks deliver real-time change events to any URL you control. Use them to integrate ChangeVault with incident management tools, custom dashboards, chat bots or internal automation.
Prerequisites
- A ChangeVault Pro plan or higher
- An HTTPS endpoint that accepts
POSTrequests
Setting up a webhook
- Go to Integrations → Automations
- Under Outgoing Webhooks, click Add webhook
- Fill in:
- Label — a name for this webhook
- URL — your HTTPS endpoint
- Events — select which events to deliver (
change.created,change.updated,change.deleted)
- Click Save
- Copy the signing secret shown immediately after creation — it is only displayed once
Save the signing secret now. It cannot be retrieved later. If lost, delete the webhook and create a new one.
Testing a webhook
Click the Test button next to any webhook to send a test payload. The test payload uses the same format as real events.
Events
| Event | Trigger |
|---|---|
change.created | A change is logged (via dashboard or API) |
change.updated | A change's title, status, risk level or other fields are updated |
change.deleted | A change is deleted |
Payload format
{
"event": "change.created",
"timestamp": "2025-04-07T10:00:00.000Z",
"data": {
"id": "uuid",
"title": "Deployed api-service v3.1.0",
"risk_level": "medium",
"status": "completed",
"organization_id": "org_...",
"service": { "id": "uuid", "name": "api-service" },
"host_ref": { "id": "uuid", "hostname": "web-01" },
"tags": ["deploy", "prod"],
"created_at": "2025-04-07T10:00:00Z"
}
}Verifying signatures
Every delivery includes an X-ChangeVault-Signature header. Verify it to confirm the request is genuine.
The signature is an HMAC-SHA256 hex digest of {timestamp}.{raw body}, where timestamp is the X-ChangeVault-Timestamp header value.
import crypto from "crypto";
export function verifyWebhookSignature(
secret: string,
rawBody: string,
timestamp: string,
signature: string
): boolean {
const payload = `${timestamp}.${rawBody}`;
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}Express.js example:
app.post("/changevault-webhook", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.headers["x-changevault-timestamp"] as string;
const signature = req.headers["x-changevault-signature"] as string;
if (!verifyWebhookSignature(process.env.WEBHOOK_SECRET!, req.body.toString(), timestamp, signature)) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body.toString());
console.log("Received event:", event.event);
res.sendStatus(200);
});Request headers
| Header | Value |
|---|---|
Content-Type | application/json |
X-ChangeVault-Event | Event name (e.g. change.created) |
X-ChangeVault-Timestamp | Unix timestamp in milliseconds |
X-ChangeVault-Signature | HMAC-SHA256 hex signature |
Delivery behaviour
- Requests time out after 10 seconds
- Failed deliveries are not retried automatically — use the Test button to re-send
- Your endpoint should return a
2xxstatus to acknowledge the delivery
See the API reference for outgoing webhooks for technical details.