Integrations

Webhooks

Push signed JSON payloads to your own endpoint whenever a signal fires - and export accounts or people as row-per-POST webhooks into tools like Clay.

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 active accounts.
  • account.suggested, Hunch surfaced a net-new suggested account (sent once per account, no matter how many signals fire for it).
  • 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"
}

account.suggested

Same data shape as signal.detected - the signal and headline describe the first signal that surfaced the account. Fired at most once per account, and only while the account is suggested; once activated, its signals arrive as signal.detected.

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-Timestampstringoptional

Unix timestamp (seconds) when the payload was signed.

X-Signal-Signaturestringoptional

Hex 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.

Exporting rows to a webhook

Beyond event notifications, Hunch pushes accounts and people to named webhook destinations as flat JSON rows - one POST per record. That is exactly what Clay, Zapier, Make, and n8n expect: each key maps to a column, each request becomes a row.

  • Add destinations in Settings → Integrations → Webhook destinations, one per target table.
  • Push any selection, saved list, or filtered view with Send to webhook - or via the REST API and MCP.
  • No size limits: pushes over 100 records run in the background and deliver every row.
  • Deliveries are signed with the destination's secret using the same headers described above.

Sending to Clay

In Clay: create a table → Add source → Import data from Webhook → copy the webhook URL. In Hunch: add it as a destination, select rows in Accounts or People, and hit Send to webhook. Each record lands as one row in your Clay table.

Account row

POST body (one per account)
{
  "record_type": "account",
  "id": "e7550358-d243-491d-9895-98005afe62bc",
  "name": "Acme Corp",
  "domain": "acme.com",
  "industry": "Software",
  "employees": 140,
  "location": "Austin, TX",
  "country": "US",
  "score": 87,
  "is_hot": true,
  "status": "active",
  "tags": "outbound, q3",
  "linkedin_url": "https://linkedin.com/company/acme",
  "short_description": "Corporate card and spend management platform.",
  "why_now": "Just raised a Series B and is scaling the GTM team.",
  "latest_signal": "Hiring 3 SDRs",
  "latest_signal_at": "2026-07-05T09:00:00Z",
  "hunch_url": "https://usehunch.co/accounts",
  "pushed_at": "2026-07-07T15:04:05Z"
}

Person row

POST body (one per person)
{
  "record_type": "person",
  "id": "3f9a1c22-0b7e-4a1d-9c2e-6d4b8f1e2a90",
  "name": "Jane Doe",
  "first_name": "Jane",
  "last_name": "Doe",
  "title": "VP Sales",
  "seniority": "VP",
  "email": "jane@acme.com",
  "phone": "+15125550100",
  "linkedin_url": "https://linkedin.com/in/janedoe",
  "location": "Austin, TX",
  "country": "US",
  "connections": 1200,
  "account_name": "Acme Corp",
  "account_domain": "acme.com",
  "account_score": 87,
  "source": "employee",
  "pushed_at": "2026-07-07T15:04:05Z"
}
Rows can occasionally be re-delivered (e.g. when a background push resumes after an interruption). Every row carries its Hunch id - dedupe on it downstream.