Webhooks send ZenABM signals to any other tool the moment an account changes, without manual exports or polling. Every Monday, when LinkedIn data syncs, webhooks fire automatically and push your data wherever you want it: Clay, Outreach, Salesloft, n8n, a Slack alert, or any prospecting and sales engagement tool with an endpoint. You get a filter builder to scope the data, and a payload builder to decide which fields go out.
What you can send
Any company-level signal ZenABM holds can go in the payload:
- Engagement data: impressions, clicks, engagements and spend over a date range you pick, with the ad sets behind them.
- Account scores: the engagement score and the account's current and lifetime ABM stage, overall and per ABM Campaign.
- Intent signals: the intents detected from ad engagement.
- Company details: name, domain, country, city, LinkedIn page, and the HubSpot company ID.
Webhooks carry LinkedIn Ads data plus ZenABM's ABM fields.
Best practices
One of the most common plays is sending your Interested Companies into any orchestration tool (this works great with Clay).
ZenABM's weekly data can trigger outreach sequences based on the Intent the engaged companies are showing, so the first message leads with the theme the account already responded to.
Webhooks are triggered every Monday, after each fresh LinkedIn data sync. You can also trigger them manually on demand. If you would rather pull than be pushed, the REST API exposes the same data, scores and intents, and the MCP server exposes them to AI agents.
The same signals can be written straight onto company records in HubSpot, Salesforce or Attio, with no endpoint to host. See CRM sync.
How to set it up
Add a webhook
Choose delivery type
Individual sends one request per company (best for Clay, Make, Zapier and n8n, one row or one scenario run per company). Batch sends a JSON array of companies, so fewer requests, but your tool needs an iterator to loop over the array. Large runs are split into several batch requests.
Pick a date range
7, 30, 90 or 180 days. All windowed metrics (clicks, impressions, cost and so on) cover this range.
Filter the data
Build conditions to narrow the data you want us to send (for example, Companies in the Interested ABM Stage).
Define payload
Test it
From the webhooks list, send a test event (up to 10 real companies) or trigger a full send manually.
Which companies are sent
Without conditions, every company in your workspace is sent, including companies with no ad activity in the date range. Those companies come through with 0 metrics and often the first stage (for example Identified). This is expected.
To send only active accounts, add a condition such as Impressions greater than 0 or ABM Stage is Interested.
Payload reference
In Individual mode, each request body is one JSON object like this. In Batch mode, the body is a JSON array of these objects. You only get the fields you selected; name and linkedInId are always sent.
{
"name": "Example Inc",
"linkedInId": "urn:li:organization:123456",
"linkedInUrl": "https://www.linkedin.com/company/123456",
"domain": "example.com",
"country": "DE",
"city": "Berlin",
"abmStage": "Aware",
"lifetimeAbmStage": "Interested",
"abmCampaigns": ["DACH Fintech"],
"abmCampaignStages": [{ "campaignId": "cmabc123", "campaign": "DACH Fintech", "stage": "Aware" }],
"intents": ["Compliance"],
"clicks": 4,
"engagements": 11,
"impressions": 820,
"costInUsd": 96.4,
"costPerClick": 24.1,
"totalClicks": 4,
"totalEngagements": 11,
"totalImpressions": 820,
"linkedInCampaignsWithClicks": ["Compliance - Video"],
"linkedInCampaignsWithEngagements": ["Compliance - Video"],
"linkedInCampaignsWithImpressions": ["Compliance - Video", "Brand - Image"],
"lifetimeEngagementScore": 3,
"hubspotCompanyId": "12345678"
}
| Field | What it contains |
|---|---|
domain | Bare domain of the company website: no https://, no www., no path. For example example.com. Empty string if unknown. Use it to match the company in your CRM. |
abmStage | Current ABM Stage, sent exactly as named on your ABM Stages page. Calculated from your ABM Campaigns, with the scope selected there and their start date. With no ABM Campaign, it is the same as lifetimeAbmStage. Empty string if none. |
lifetimeAbmStage | Lifetime ABM Stage. Not limited in scope, and starts about 90 days before you signed up. It never goes down, so it shows how far the company ever got across all your motions. |
abmCampaignStages | One entry per ABM Campaign the company belongs to, with its stage inside that campaign (same stage names). Not limited by the webhook's campaign selection. Empty array until you create an ABM Campaign, or if the company is in none. |
abmCampaigns | Names of the ABM Campaigns the company belongs to. |
intents | Names of the intents detected for the company. |
clicks, engagements, impressions, costInUsd, costPerClick | Activity in the webhook's date range. See the next section for scope. |
totalClicks, totalEngagements, totalImpressions | Company-wide activity in the same date range. See the next section. |
linkedInCampaignsWith… | Names of the LinkedIn ad sets that got clicks, engagements or impressions from the company. |
lifetimeEngagementScore | Whole number from 1 to 5, based on all LinkedIn interactions. Not affected by the date range. |
hubspotCompanyId | ID of the matched HubSpot company. Empty string if there is no match. |
clicks vs. totalClicks
Both use the same date range. "Total" does not mean lifetime.
clicks,engagements,impressions: activity on the campaigns, ad sets or ABM Campaigns you selected on the webhook. With no campaign selection, they equal the company-wide numbers.totalClicks,totalEngagements,totalImpressions: company-wide activity across all your LinkedIn ads. They are only sent when the webhook has no campaign selection.
For a weekly overwrite in your CRM, use clicks, engagements and impressions. They are always present and match your campaign selection.
Useful CRM fields for campaign performance
To judge campaign performance per account, send abmStage, engagements, clicks, lifetimeEngagementScore, intents and abmCampaignStages. Add lifetimeAbmStage to see how far each company ever got.
You can read performance without one, but an ABM Campaign groups your
LinkedIn campaigns under one ABM motion, gives a per-campaign stage view, and fills abmCampaigns
and abmCampaignStages in the webhook. If you have one target account list, the simplest setup is
one ABM Campaign that holds all your LinkedIn campaigns.
Delivery, responses and retries
Webhooks send a POST with a JSON body every Monday, after the weekly LinkedIn sync.
- Success: any
2xxresponse. - Timeout: 30 seconds per request.
429: we back off and retry the same request, up to 8 times, then continue the run later.5xx,408, timeout or network error: we retry the whole run once, after about 1 to 5 minutes. Failures after that retry are final.404: no retry, and the webhook is turned off. Check the URL and turn it back on.400,403,413: no retry.
A run stops early after the first 404, after 3 400/403 responses in a row, or after 3 network errors in a row.
If your tool needs more than 30 seconds to process a company, answer 200 right away and do the
work afterwards.
Changing a webhook later
You can edit an existing webhook at any time: add or remove payload fields (for example intents, abmCampaigns, abmCampaignStages or costInUsd), change conditions, the date range or the URL. You do not need a new webhook. The next send uses the new settings.
Example: Make.com to Pipedrive
This recipe updates existing Pipedrive organizations with ZenABM data every week. It does not create new organizations.
Create the scenario in Make
Add a Webhooks → Custom webhook trigger and copy its URL.
Create the webhook in ZenABM
Paste the URL. Pick Individual delivery, so each company starts one scenario run. Select
domain plus the fields you want in Pipedrive. Add a condition such as Impressions greater
than 0 to skip inactive companies.
Send a test event
Find the organization
Add a Pipedrive Search for organizations module. Search by the domain field (or by name
if your organizations have no domain field).
Update it
Add a filter that continues only when an organization was found. Then add a Pipedrive Update an organization module and map the ZenABM fields to your custom fields.
The same pattern (webhook trigger → search by domain → update) works in Zapier and n8n.