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
- In the sidebar, open API and choose the Webhooks tab.
- 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_upandcredits.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.
- Copy the signing secret. It's shown only once. Store it where your endpoint can read it.
- Press Send test. Your endpoint gets a
webhook.testevent 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:
{
"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:
- Take
tand the raw request body, before you parse the JSON. - Compute HMAC-SHA256 of
<t>.<body>with your signing secret, as hex. - Compare it with each
v1value, in constant time. One must match. - Refuse the request if
tis more than 5 minutes from now.
In Node.js:
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:
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.
Webhooks are also available in the API: see Webhooks in the API docs.