ErgOpsDocs

Verify webhook signatures

Each request includes:

  • X-ErgOps-Webhook-Id: stable event UUID; deduplicate it.
  • X-ErgOps-Webhook-Timestamp: Unix seconds.
  • X-ErgOps-Webhook-Signature: v1= plus lowercase HMAC-SHA256 hex.

The signed bytes are ${timestamp}.${rawBody}. Verify against the raw body before JSON parsing using a constant-time comparison. Reject stale timestamps; five minutes is the recommended default tolerance unless your risk policy requires less.

const expected = crypto.createHmac("sha256", process.env.ERGOPS_WEBHOOK_SECRET)
  .update(`${timestamp}.${rawBody}`).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(signature.slice(3), "hex"), Buffer.from(expected, "hex"));

Webhook signing secrets must be recoverable by the delivery runtime, so ErgOps encrypts them at rest with a deployment-held key. API authentication secrets are different: only their irreversible hash is retained.