Integrations
Webhooks
Push signed JSON payloads to your own endpoint whenever a signal fires or a digest is ready.
Setup
In Settings → Integrations, add your Webhook URL and enable it. Hunch generates a signing secretshown in the same panel, you'll use it to verify every request. Use Test to send a sample payload.
Webhook URLs must be public
https endpoints. Internal, loopback, and private addresses are rejected to prevent SSRF.Events
Every delivery has an event field. The event types are:
signal.detected, a signal fired on one of your accounts.daily.digest, the once-daily summary.
Payload shape
All payloads share a common envelope:
Envelope
{
"event": "signal.detected",
"workspace_id": "d347bc8c-1288-439b-8a45-57998aff0c6c",
"timestamp": "2026-07-03T18:34:07.971Z",
"data": { /* event-specific */ }
}signal.detected
data
{
"account": {
"id": "e7550358-d243-491d-9895-98005afe62bc",
"name": "Ramp",
"domain": "ramp.com"
},
"signal": {
"id": "3f9a1c22-0b7e-4a1d-9c2e-6d4b8f1e2a90",
"name": "New Revenue Leader"
},
"headline": "New CRO hired, pipeline build begins",
"alpha": 88,
"run_id": "8c1e5b90-2a44-4f3e-9b21-7a05843f021c"
}daily.digest
data
{
"total_signals": 12,
"total_suggested": 5,
"signals": [
{
"accountId": "acc_...",
"accountName": "Ramp",
"accountDomain": "ramp.com",
"logoUrl": "https://...",
"signalName": "New Revenue Leader",
"headline": "New CRO hired, pipeline build begins",
"alpha": 88
}
],
"suggested": [
{ "name": "Acme", "domain": "acme.com", "industry": "SaaS", "employees": 400 }
]
}Verifying signatures
Each request carries two headers:
X-Signal-TimestampstringoptionalUnix timestamp (seconds) when the payload was signed.
X-Signal-SignaturestringoptionalHex HMAC-SHA256, prefixed with sha256=.
Compute the expected signature as HMAC-SHA256(secret, `${timestamp}.${raw_body}`)and compare it to the header. Reject the request if they don't match.
Node.js verification
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(req, rawBody, secret) {
const ts = req.headers["x-signal-timestamp"];
const sig = String(req.headers["x-signal-signature"]).replace(/^sha256=/, "");
const expected = createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"));
}Verify against the raw request body, before any JSON parsing or re-serialization, a re-encoded body will not match the signature.
Delivery behavior
- Requests time out after 10 seconds; a slow endpoint won't hold up your alerts.
- Non-2xx responses are logged. Design your receiver to be idempotent.
- Which events fire is governed by your notification content toggles.