Webhooks
Webhooks notify your systems when records change. Configure an endpoint URL, pick the events to subscribe to, and EndpointOS POSTs a signed JSON payload to your URL.
Creating an endpoint
Open the Webhooks tab on a project, click New endpoint, paste your HTTPS URL, pick the events. The signing secret is shown once. Copy it now.
Signature verification
Every delivery includes an X-EndpointOS-Signature header containing an HMAC-SHA256 of the raw request body, computed with your signing secret. The format mirrors Stripe's pattern (t=timestamp,v1=hex). Verify it before trusting the payload:
const sig = req.headers["x-endpointos-signature"];
const [tsPart, v1Part] = sig.split(",");
const timestamp = tsPart.split("=")[1];
const provided = v1Part.split("=")[1];
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(timestamp + "." + rawBody)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(provided), Buffer.from(expected))) {
return res.status(401).end();
}SSRF protection
Endpoint URLs are validated on save and re-validated on every fire. Internal addresses (RFC1918 private ranges, link-local, loopback, IPv4-mapped IPv6) are rejected. This protects your team from accidentally pointing a webhook at an internal service.
Delivery + retries
Each delivery attempt is recorded in the endpoint's delivery log: timestamp, response status, response body (truncated), duration. Today, delivery is fire-and-forget; durable retry with exponential backoff is on the next-up roadmap (see /changelog). Plan accordingly: webhooks are best-effort notifications, not a system of record.
Rotating + disabling
Rotate the signing secret from the endpoint's settings (issues a new secret, invalidates the old). Disable the endpoint to pause all delivery without deleting its history.