Docs
Get API key

Webhooks

Check the signature

The signature is the hex HMAC-SHA256 of the timestamp, a dot and the raw body, made with the webhook’s signing secret (whsec_…, shown once when the webhook is added). Refuse requests whose timestamp is more than 5 minutes old.

Lost the secret? New signing secret in the webhook’s window makes another one, shown once. The old one stops matching right away.

Node.js
import crypto from "node:crypto";

// rawBody: the request body exactly as received, before any JSON parsing.
export function fromSalesteam(rawBody, headers, secret) {
  const timestamp = headers["x-salesteam-timestamp"] || "";
  const expected = "v1=" + crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const given = headers["x-salesteam-signature"] || "";
  const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
  return fresh && given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
Python
import hashlib, hmac, time

# raw_body: the request body exactly as received (bytes), before any JSON parsing.
def from_salesteam(raw_body: bytes, headers, secret: str) -> bool:
    timestamp = headers.get("X-Salesteam-Timestamp", "")
    expected = "v1=" + hmac.new(secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    fresh = timestamp.isdigit() and abs(time.time() - int(timestamp)) < 300
    return fresh and hmac.compare_digest(expected, headers.get("X-Salesteam-Signature", ""))