The competitor report has its own webhook, configured separately:
competitor_monitoring.report_ready.
Request
Every request is aPOST with a JSON body and these headers:
Header names are case-insensitive. Any
2xx answer counts as delivered.
competitor_monitoring.account_alert
One per account per monitoring run, for the Defense and Attack alerts: the account and every
person a competitor engaged there in the alert’s period.
Only their people’s own actions count: a like or comment by someone at the account on the
competitor’s post never alerts. A pleasantry (“Congrats!”) counts as a like. Defense alerts on
its rule. Attack alerts on its rule only when their sales team is prospecting the account
(account.reading is prospecting), and on any pitch. On both, a comment on a post that shows
buying intent alerts on its own.
competitor_monitoring.alert
One schema for all three alert types. Every field is always present: a field that does not
apply to the alert type is null, never missing.
direction is outbound when the competitor’s salesperson engaged the person’s post, and
inbound when the person engaged the salesperson’s post.
Attack covers every non-customer account, and account_scope says which kind it is, so you
can route them apart: target for the accounts on your target account list, other for every
other account a competitor engages with (someone matching your buyer titles). Slack posts and
emails say the same as “Target account” or “Other account”. To stop the alerts on other
accounts, set attack_other_accounts to false with
Update Competitor Alerts. account_scope and
account.is_target are new fields (as is account.clustr_account_id): a receiver that ignores unknown keys keeps working.
The owner comes from your CRM and nothing else: the company owner field for Attack, and the CS
owner field (company_cs in Set Owner Field Mappings)
for Defense. Clustr reads it from your CRM when it sends the alert. If your CRM cannot be
reached at that moment, it uses the owner from the last CRM sync instead.
defense_interaction
Someone at one of your customers interacted with a competitor’s salesperson. Every retained
interaction alerts, likes included, in both directions. Each interaction alerts once.
attack_critical_comment
A competitor’s salesperson left a comment classified as critical (a meeting request, a
comparison, an objection handled, and so on) on the post of someone at a non-customer account.
attack_engagement_threshold
A non-customer account reached your threshold: at least attack_threshold_interactions
interactions over attack_threshold_days days (10 in 30 by default), with one competitor’s
team (attack_threshold_scope per_competitor, the default) or with all your competitors
together (all_competitors). There is no cooldown: the alert is sent again after every
collection run while the account stays at or above the threshold, each time with a new
alert_id.
attack_critical_comment with made-up values, plus "test": true.
competitor_monitoring.team_refresh
Sent once after each finished team refresh of a competitor. The same recap is posted once to
each distinct Slack channel you configured. A follow-up employment check (a profile checked again
a few days after a refresh could not place it) that finds a leaver or a role change sends one
too, with joiners at 0.
Signature
When a webhook secret is saved, every request carriesX-ClustR-Signature:
v1 is the hex HMAC-SHA256 of <t>.<raw body>, keyed with your secret. It is computed on each
attempt, over the exact bytes sent, so verify against the raw request body before parsing it.
Compare in constant time, and reject a t older than a few minutes to stop replays.
Delivery and retries
Webhooks go through a queue, so they leave Clustr within a few seconds, not in the same instant as the Slack post.- Up to 3 attempts. A failed attempt is retried after 5 seconds, then after 20 seconds. After the third failure the delivery is dropped.
- Within one attempt, a
408,429,500,502,503or504answer is retried a few times with a short backoff before the attempt counts as failed. - 30-second timeout per request.
- Once per alert. An alert is queued at most once per URL. A retry can still deliver the
same alert twice if your endpoint timed out after processing it, so dedupe on
alert_id(oridfor a team refresh).