Send signals to a webhook

Updated Nov 20263 min read

A webhook sends each new signal to a URL of yours the moment a monitor flags it: a post, or a comment the person wrote under someone else's post. Use it to create a task in your CRM, start a Zapier or Make scenario, or alert your team.

Add a webhook

  1. In the sidebar, open API and choose the Webhooks tab.
  2. Press Add webhook, paste your endpoint URL and pick the events (all of them by default):
    • signal.created: a monitor flagged a post or a comment.
    • credits.topped_up and credits.auto_topup_failed: auto top-up bought a pack, or its payment failed. These are for the whole account, whichever client the webhook belongs to.
  3. Copy the signing secret. It's shown only once. Store it where your endpoint can read it.
  4. Press Send test. Your endpoint gets a webhook.test event and you see what it answered.

The URL must start with https:// and be reachable on the public internet. Addresses on private networks aren't allowed.

A webhook belongs to the client (workspace) you're in when you add it, and gets only that client's signals. You can have up to 10 per client.

What we send

Each event is a POST with a JSON body:

JSON
{
  "id": "sig_6f1c…",
  "type": "signal.created",
  "created_at": "2026-11-02T09:14:03Z",
  "workspace_id": "…",
  "data": {
    "signal": {
      "id": "6f1c…",
      "kind": "comment",
      "text": "We're moving off our data vendor next quarter…",
      "reason": "They're switching vendors: \"moving off our data vendor next quarter\"",
      "post_url": "https://www.linkedin.com/feed/update/urn:li:activity:…/",
      "author": { "name": "Dana Ross", "headline": "CRO at Acme", "url": "https://www.linkedin.com/in/danaross/" },
      "parent_post": { "text": "What's your outbound stack in 2026?", "author_name": "Sam Lee", "url": "…" }
    },
    "monitor": { "id": "…", "name": "Dana Ross", "type": "profile", "icp_id": "…" }
  }
}

kind is post or comment. For a comment, text is the comment and parent_post is the post it was under.

Check that a request came from filtrat

Every request has a Filtrat-Signature header like t=1767345243,v1=5257a8…. To check it:

  1. Take t and the raw request body, before you parse the JSON.
  2. Compute HMAC-SHA256 of <t>.<body> with your signing secret, as hex.
  3. Compare it with each v1 value, in constant time. One must match.
  4. Refuse the request if t is more than 5 minutes from now.

In Node.js:

JavaScript
const crypto = require("crypto");

function isFromFiltrat(rawBody, header, secret) {
  const t = header.match(/t=(\d+)/)?.[1];
  const sigs = [...header.matchAll(/v1=([a-f0-9]+)/g)].map((m) => m[1]);
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return sigs.some((s) => s.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

In Python:

Python
import hashlib, hmac, re, time

def is_from_filtrat(raw_body: bytes, header: str, secret: str) -> bool:
    t = re.search(r"t=(\d+)", header)
    if not t or abs(time.time() - int(t.group(1))) > 300:
        return False
    expected = hmac.new(secret.encode(), t.group(1).encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(s, expected) for s in re.findall(r"v1=([a-f0-9]+)", header))

Answer quickly

Reply with any 2xx status within 10 seconds, then do the work. Anything else (an error, a redirect, a timeout) is sent again after 1 minute, 5 minutes, 30 minutes, then 1, 2, 4, 8 and 8 hours. Retries carry the same body and the same Filtrat-Event-Id header: if you've seen that id, skip it.

If a webhook keeps failing for 3 days with no successful delivery, we turn it off and email you. Fix the endpoint, press Send test to check it, then Turn on. Signals from while it was off aren't sent.

Delivery log

Press Deliveries on a webhook to see the last 30 days: each event, its status (delivered, pending with the next retry time, failed or cancelled), the attempts and what your endpoint answered. Click an event to see the body sent. Resend sends the same event again.

Rotate the secret

Press the rotate button to get a new secret, shown once. For the next 24 hours requests are signed with both the new and the old secret (two v1 values), so you can update your endpoint without missing events.

Tip

Webhooks are also available in the API: see Webhooks in the API docs.

Was this helpful?
Still stuck?

Email support@filtrat.io with the list or job name and what you expected to see.

Contact support
MYKHAILO BURIAK · NIP: 8982334042 · REGON: 544788490 · ul. Mieszczańska 18/40, 50-201 Wrocław, Poland© 2026 filtrat.io