Lead events
Webhooks fired by the Leads product. See Webhooks overview for setup, envelope format, signature verification, retries, and security.
Each webhook subscribes to one or more event types. Subscriptions are independent: a webhook that only subscribes to lead2.created will never receive activity.detected, and vice versa.
| Event | When it fires | Volume |
|---|---|---|
lead2.created | The first time a person is seen as a lead for your brand. Fires once per person, ever. | Low |
activity.detected | Every time a tracked person comments, reacts, or reposts on your tracked content. Fires for the first engagement and every subsequent one. Payload includes an isFirstActivity flag so you can distinguish first-touch. | High |
The engagements array​
Both events ship an engagements array. Every field below is also available on the public REST API (GET /signal-leads/:id and GET /signal-leads), in the same shape — one parser works for the webhook and the API.
postAuthorDetail and source were webhook-only when they shipped. They are now on the REST API too, but opt-in there: pass includeEngagementDetail=true (alongside includeEngagements=true on the list endpoint). On the webhook they are always sent, no flag involved.
| Field | Type | Description |
|---|---|---|
id | string | Engagement id |
type | string | null | comment / reaction / repost |
reactionType | string | null | e.g. LIKE, EMPATHY (only when type is reaction) |
commentText | string | null | Sanitized comment text (only when type is comment) |
postUrl | string | null | The post that was engaged with |
postContent | string | null | Text content of the social post |
postPostedAt | string | null | When the post was originally published (ISO 8601) |
postAuthor | string | null | Display name of the post author |
postAuthorDetail | object | null | Structured post author — see below |
source | object | null | What the signal was watching when it found this post — see below |
signal | object | null | The signal that triggered detection (id, name, signalType) |
emittedAt | string | null | When the signal emission was created (ISO 8601) |
trackedAt | string | When Limelight detected the engagement (ISO 8601) |
activity.detected always sends a single-item engagements array — the engagement that triggered the event. lead2.created includes up to 20 most-recent engagements known for the lead at delivery time.
source — which competitor a post came from​
For competitor signals (posts-from-their-competitors-pages, posts-that-mention-competitors, posts-from-competitors-employees), source.value is the exact LinkedIn URL you configured for that signal. That is the reliable way to attribute a post to a competitor — signal.name only tells you which signal fired, not which entry in it.
| Field | Type | Description |
|---|---|---|
id | string | null | Internal id of the tracked entry |
type | string | null | li-company-url, li-company-mention, li-profile-url, post-url, posts-with-keywords |
value | string | null | The LinkedIn URL you configured for this signal |
liCompanyId | string | null | LinkedIn numeric company id, on company-mention entries |
company | object | null | Resolved company record for that page, when we have one |
type tells you how to read value: the two li-company-* types point at a company page (the competitor itself), while li-profile-url points at a person you asked us to track. post-url and posts-with-keywords signals are not competitor-scoped and carry no company.
postAuthorDetail — who wrote the post​
| Field | Type | Description |
|---|---|---|
name / firstName / lastName | string | null | Author name |
headline | string | null | LinkedIn headline, e.g. "VP Sales at Acme" |
username | string | null | LinkedIn vanity name |
linkedinProfileUrl | string | null | Author's profile URL |
profileImageUrl | string | null | Author's avatar |
company | object | null | The author's employer — see the caveat below |
leadId | string | null | The author's own lead id in your brand, when they are one |
company is only populated when the post author is also a tracked lead in your brand, because that is the only place we hold a structured employer for them. Expect it on roughly a third of engagements. When it is null, headline usually names the employer in free text, and for competitor signals source is the more reliable attribution.
The company object on both source and postAuthorDetail uses the same shape as company on GET /signal-leads/:id: id, name, url, homepageUrl, logoUrl, industry, staffCountRange, staffCount, location, country, city, username, description.
postAuthor keeps its existing string | null shape — it is still the author's display name. postAuthorDetail and source are new sibling keys. Every other v1 field is unchanged, and the envelope is still "version": "1".
lead2.created​
{
"id": "wh_...",
"event": "lead2.created",
"version": "1",
"createdAt": "2026-04-16T10:22:00.000Z",
"brandId": "brand_abc",
"data": {
"lead2": {
"id": 1234,
"extId": "li-foo",
"name": "Alice Example",
"headline": "CTO at Example",
"username": "alice",
"title1": "CTO",
"liProfileUrl": "https://linkedin.com/in/alice",
"profileImgUrl": "https://cdn/img.jpg",
"leadCompany": {
"id": 98,
"name": "ACME Corp",
"domain": "acme.com"
}
},
"engagements": [
{
"id": "9876",
"type": "comment",
"reactionType": null,
"commentText": "Love this!",
"postUrl": "https://www.linkedin.com/feed/update/1",
"postContent": "Excited to share our latest B2B creator partnership results...",
"postPostedAt": "2026-04-15T08:00:00.000Z",
"postAuthor": "Pat Author",
"postAuthorDetail": {
"name": "Pat Author",
"firstName": "Pat",
"lastName": "Author",
"headline": "Account Executive at Clay",
"username": "patauthor",
"linkedinProfileUrl": "https://www.linkedin.com/in/patauthor",
"profileImageUrl": "https://cdn/pat.jpg",
"company": null,
"leadId": null
},
"source": {
"id": "2133",
"type": "li-company-url",
"value": "https://www.linkedin.com/company/fullenrich/",
"liCompanyId": null,
"company": {
"id": "18402",
"name": "FullEnrich",
"homepageUrl": "https://fullenrich.com",
"industry": "Computer Software",
"staffCount": 42,
"username": "fullenrich"
}
},
"signal": { "id": "42", "name": "DevOps influencers", "signalType": "keyword" },
"emittedAt": "2026-04-15T09:30:00.000Z",
"trackedAt": "2026-04-16T10:21:50.000Z"
}
]
}
}
activity.detected​
{
"id": "wh_...",
"event": "activity.detected",
"version": "1",
"createdAt": "2026-04-16T10:22:00.000Z",
"brandId": "brand_abc",
"data": {
"isFirstActivity": true,
"lead2": { /* same shape as lead2.created */ },
"engagements": [
{
"id": "9876",
"type": "comment",
"reactionType": null,
"commentText": "Love this!",
"postUrl": "https://www.linkedin.com/feed/update/1",
"postContent": "Excited to share our latest B2B creator partnership results...",
"postPostedAt": "2026-04-15T08:00:00.000Z",
"postAuthor": "Pat Author",
"postAuthorDetail": {
"name": "Pat Author",
"firstName": "Pat",
"lastName": "Author",
"headline": "Account Executive at Clay",
"username": "patauthor",
"linkedinProfileUrl": "https://www.linkedin.com/in/patauthor",
"profileImageUrl": "https://cdn/pat.jpg",
"company": null,
"leadId": null
},
"source": {
"id": "2133",
"type": "li-company-url",
"value": "https://www.linkedin.com/company/fullenrich/",
"liCompanyId": null,
"company": {
"id": "18402",
"name": "FullEnrich",
"homepageUrl": "https://fullenrich.com",
"industry": "Computer Software",
"staffCount": 42,
"username": "fullenrich"
}
},
"signal": { "id": "42", "name": "DevOps influencers", "signalType": "keyword" },
"emittedAt": "2026-04-15T09:30:00.000Z",
"trackedAt": "2026-04-16T10:21:50.000Z"
}
]
}
}
Manual resend​
From the Lead Feed, open any lead's ⋯ menu and choose Send to webhook to re-push lead2.created or the most recent activity.detected to a webhook of your choice.
See Manual resend in the overview for general rules (retention, rate limits).
Notes​
- Internal source metadata is never sent in webhook payloads. Only the documented, normalized subset is included (
commentText,reactionType,postUrl,postContent,postAuthor,postAuthorDetail,source,signal,emittedAt). In particular,sourceexposes only the LinkedIn URL you configured for the signal plus public company data — never another brand's configuration, and never the raw scrape output.