Webhooks
Webhooks let Ventryx push real-time event notifications to your server as HTTP POST requests, eliminating the need to poll the API for state changes.
Registering an endpoint
curl
curl -X POST https://api.ventryx.io/v1/webhooks \
-H "Authorization: Bearer $VENTRYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/ventryx",
"events": ["workflow.completed", "approval.requested", "api_key.revoked"]
}'
To subscribe to all events, pass "events": ["*"].
Webhook payload
Each delivery is a POST request with JSON body and the following headers:
Request headers
Content-Type: application/json Ventryx-Event: workflow.completed Ventryx-Delivery: del_01HXYZ Ventryx-Signature: sha256=a1b2c3d4...
Payload body
{
"id": "evt_01HXYZ",
"type": "workflow.completed",
"created_at": "2026-04-03T09:15:00.000Z",
"data": {
"workflow_id": "wf_01HABC",
"run_id": "run_01HDEF",
"status": "success"
}
}
Signature verification
Verify the Ventryx-Signature header on every delivery using your webhook secret. Reject any request that fails verification.
Node.js
const crypto = require('crypto');
function isValidSignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your request handler:
app.post('/webhooks/ventryx', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['ventryx-signature'];
if (!isValidSignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// handle event...
res.status(200).send('ok');
});
Retries
If your endpoint returns a non-2xx status or times out (10s limit), Ventryx retries the delivery with exponential backoff — up to 5 attempts over ~2 hours. Delivery logs are available in the dashboard under Settings → Webhooks → Delivery history.