Documentation
Receive every event at your own URL as it happens.
Add one in Settings, with Create a webhook, or with the needleCreateWebhook MCP tool. Any member of the workspace can add webhooks. Only the member who added a webhook can change it; they or a workspace admin can delete it. A workspace can have up to 5, and each one gets every event type the member who created it can see. When that member leaves the workspace, their webhooks are deleted.
The URL must start with https://. When you add a webhook you get its signing secret, which starts with whsec_. It is shown only this once, so store it where your receiver can read it.
Each event is one POST with a JSON body:
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_received",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_received",
"label": "Reply received",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"data": { "text": "Hello!" }
}
}data is the same event object that Search events returns. timestamp is when the event happened. The event's own data field depends on its type; see Event types.
Each request also has these headers:
webhook-id: the event id. It stays the same when a request is sent again.webhook-timestamp: when this request was sent, in Unix seconds.webhook-signature: v1, followed by a base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body}, keyed with your secret.The headers follow Standard Webhooks, so its libraries can check them. A request that fails the check did not come from Needle. The libraries also refuse a request whose webhook-timestamp is more than 5 minutes from your server's clock, so a captured request can't be sent again later.
Pass the raw body, before any JSON parsing, and the request headers to verify().
import express from 'express'
import { Webhook } from 'standardwebhooks'
const webhook = new Webhook(process.env.NEEDLE_WEBHOOK_SECRET)
const app = express()
app.post('/webhooks/needle', express.raw({ type: 'application/json' }), (req, res) => {
let event
try {
event = webhook.verify(req.body, req.headers)
} catch {
return res.status(400).end()
}
res.status(204).end()
// Handle the event here, after answering.
})Standard Webhooks has libraries for other languages.
If your endpoint requires its own key, such as Authorization: Bearer <your key>, add it as a header in Settings, or with headers in Create a webhook or Update a webhook. Needle sends it with every request.
null.content-type, content-encoding, user-agent, the webhook- headers, and connection headers such as host.Headers are not part of the signature, so verifying requests works the same way.
An event fails when your URL doesn't answer with a 2xx within 10 seconds. A failed event is tried 3 times: right away, 10 minutes later, and 1 hour after the first try. After the 3rd failure it is not sent again. An event that has not been delivered after 3 days is given up without further tries.
If your URL answers 429, we stop sending to it for a few seconds. The events that got the 429 are tried again on the schedule above.
Missed events are still in the event log. Fetch them with Search events.
Delivery is at least once: after a crash on our side, an event you already got can arrive again. Use webhook-id to skip events you have already handled.
Events are not sent in order: up to 5 requests to your URL can be open at once, and a retried event can arrive after newer ones. Use timestamp for the order in which things happened.
Change the URL or the headers in Settings, or with Update a webhook. Events not yet delivered go out with the new URL and headers, and the secret stays the same.
Deleting a webhook stops its deliveries, and events not yet delivered to it are dropped. If you lose the secret, delete the webhook and add it again to get a new one.
Search events, the MCP tools, and webhooks all use the same event object. nodeId is the campaign step, enrollmentId is the lead's run through a campaign, and label is the name the app shows for the type. What data holds depends on type.
To match a lead in your own system, fetch it by leadId with Get a lead: it returns the lead's email (when known) and its LinkedIn and Instagram identities.
| Type | When it is sent |
|---|---|
lead_created | A lead was created, from the app, the API, MCP, an import, or a direct message to someone who was not a lead yet. |
lead_updated | A lead's details or handles changed; data.changes lists each changed field. |
lead_deleted | A lead was deleted. Its live campaigns stop with exitReason lead_deleted. |
lead_enrolled | A lead was added to a campaign. |
lead_skipped | A lead was not added to a campaign; data.skipReason says why. |
message_generated | AI wrote a message for a step. |
condition_evaluated | A check in the sequence was evaluated. |
task_held | A step is waiting for approval. |
task_approved | A held step was approved. |
task_skipped | A step was skipped; data.skipReason says why. |
task_cancelled | A step was cancelled before it ran. |
task_failed | A step failed; data.errorKind says why. |
enrollment_waiting | The sequence is waiting, for example for a reply. |
enrollment_completed | The lead reached the end of the sequence. |
enrollment_stopped | The sequence stopped early; data.exitReason says why. |
lead_suppressed | A lead matched a suppression. |
campaign_status_changed | A campaign's status changed, for example it was started or paused. |
campaign_updated | A campaign's name, sequence, schedule, limits or suppression policy was edited; data.changedFields lists which. |
account_connected | A LinkedIn or Instagram account was connected to the workspace for the first time, or again after it was deleted. |
account_reconnected | A disconnected account works again, because a member signed in to it again or LinkedIn or Instagram reports it healthy. |
account_deleted | A connected account was deleted. |
account_paused | A connected account was paused, by its owner or after hitting a limit (data.errorKind). |
account_resumed | A paused connected account was resumed, by its owner or when billing was restored. |
account_disconnected | A connected account stopped working: it needs signing in again (data.errorKind is auth_required) or LinkedIn or Instagram disconnected it (disconnected). Its campaigns wait until it is reconnected. |
account_suspended | A connected account was signed out and stopped, because the workspace's billing lapsed or its owner was removed from the workspace (data.message). It has to be connected again to be used. |
account_limits_updated | A connected account's usage limits were changed; data.changes lists each limit. |
account_access_granted | A member (data.member) was allowed to use a connected account. |
account_access_revoked | A member (data.member) can no longer use a connected account. Campaigns they started with it pause. |
account_sharing_changed | A connected account was shared with the whole workspace, or stopped being shared. |
member_invited | Someone was invited to the workspace. |
member_invitation_revoked | An invitation to the workspace was withdrawn. |
member_joined | Someone accepted an invitation and joined. |
member_role_changed | A member's role changed. |
member_removed | An admin removed a member. Their accounts are suspended and their campaigns pause. |
member_left | A member deleted their Needle account. |
api_key_created | An API key was created. |
api_key_revoked | An API key was disabled. |
api_key_enabled | A disabled API key was enabled again. |
api_key_deleted | An API key was deleted. |
webhook_created | A webhook was added. |
webhook_updated | A webhook's URL or headers changed; data.changedFields lists which. |
webhook_deleted | A webhook was removed. |
suppression_added | A lead or company was added to the do-not-contact list by a member or through the API. |
suppression_removed | An entry was removed from the do-not-contact list. |
linkedin_profile_visited | A LinkedIn profile was visited. |
linkedin_invite_sent | A LinkedIn connection request was sent. |
linkedin_invite_withdrawn | A LinkedIn connection request was withdrawn. |
linkedin_message_sent | A LinkedIn message was sent, through Needle or by the account owner in LinkedIn (data.sentOutsideNeedle). |
linkedin_follow_sent | A LinkedIn profile was followed. |
linkedin_unfollowed | A LinkedIn profile was unfollowed. |
linkedin_invite_accepted | A LinkedIn connection request was accepted. |
linkedin_message_received | A LinkedIn reply was received. |
linkedin_post_commented | A comment was posted on LinkedIn. |
linkedin_post_reacted | A reaction was added to a LinkedIn post. |
instagram_message_sent | An Instagram message was sent, through Needle or by the account owner in Instagram (data.sentOutsideNeedle). |
instagram_profile_visited | An Instagram profile was visited. |
instagram_follow_sent | An Instagram profile was followed. |
instagram_unfollowed | An Instagram profile was unfollowed. |
instagram_message_received | An Instagram reply was received. |
instagram_post_commented | A comment was posted on Instagram. |
instagram_post_reacted | An Instagram post was liked. |
instagram_message_reacted | A reaction was added to an Instagram message. |
instagram_post_created | An Instagram post was published. |
What a connected account says or does on LinkedIn or Instagram is account-sensitive: linkedin_profile_visited, linkedin_invite_sent, linkedin_invite_withdrawn, linkedin_message_sent, linkedin_follow_sent, linkedin_unfollowed, linkedin_invite_accepted, linkedin_message_received, linkedin_post_commented, linkedin_post_reacted, instagram_message_sent, instagram_profile_visited, instagram_follow_sent, instagram_unfollowed, instagram_message_received, instagram_post_commented, instagram_post_reacted, instagram_message_reacted, instagram_post_created.
task_held, account_connected, or member_invited.Search events and the MCP tools follow these rules for whoever calls them. A webhook receives what the member who created it can see, and is deleted when that member leaves the workspace. For everything else access covers, see Who can do what.
| Field | Meaning |
|---|---|
action | The action Needle took. One of: linkedin_invitation, linkedin_cancel_invitation, linkedin_message, linkedin_inmail, linkedin_profile_view, linkedin_comment, linkedin_reaction, instagram_message, instagram_profile_view, instagram_follow, instagram_unfollow, instagram_comment, instagram_reaction, instagram_post. |
text | The text sent, received, or written by AI: a message, connection note, comment, or caption. |
subject | The subject line of an InMail. |
message | A short note from Needle, for example why a step was cancelled or a status change such as draft -> active. |
skipReason | Why the lead or step was skipped. One of: duplicate_in_batch, enrolled_elsewhere, suppressed, recently_contacted, unresponsive, daily_limit_reached, lead_not_found, missing_identity, missing_personalization, already_connected, already_invited, already_following, follow_request_pending, not_first_degree, invalid_recipient, generation_failed. |
exitReason | Why the sequence ended. One of: finished, replied, messaged_directly, timeout, manual, suppressed, dead_end, error, account_disconnected, campaign_archived, lead_deleted. |
suppressionReason | Which kind of suppression matched. One of: manual, unsubscribed, not_interested, existing_customer, open_opportunity, competitor, employee, invalid_recipient, complained, recently_contacted, unresponsive. |
keyword | The opt-out phrase found in the reply, for example unsubscribe. |
errorKind | A short error code, for example rate_limited, auth_required, or invalid_recipient. New codes can appear. |
profile | An object about the person: who the action was aimed at, or who replied or accepted. It has name, identity (the LinkedIn public identifier or Instagram username, or the user id when there is none), url, and imageUrl. All but identity can be null. |
changes | An object keyed by changed field, each { "from": ..., "to": ... } with string or null values. On lead_updated the keys are the lead fields (firstName, lastName, companyName, companyDomain, jobTitle, email, timezone), the handles (linkedin, instagram), and properties.<key> for custom properties. On account_limits_updated they are `<action>.<hour |
changedFields | The fields that changed when their values are too large or too secret to include: name, graph, schedule, limits, suppressionPolicy for a campaign, url and headers for a webhook. |
member | The workspace member the event is about, as { "userId": ..., "name": ... }. actorUserId is who made the change. |
email | The email address an invitation was sent to. |
role | The workspace role: member, admin, or owner. |
apiKey | The API key the event is about, as { "id": ..., "name": ... }. The key itself is never included. |
webhook | The webhook the event is about, as { "id": ..., "host": ... }. Only the URL's host is included, since URLs can hold tokens. |
suppressionId | The do-not-contact entry the event is about. |
companyDomain | The company domain a do-not-contact entry covers. |
properties | An object of strings, with the keys listed under each type below: branch (yes or no), edited (true or false), waitingFor (the event the sequence waits for), timeoutAt and pausedUntil (ISO 8601 times). |
Set lists which of leadId, campaignId, enrollmentId, connectedAccountId, channel, and nodeId the type fills in; the others are null. leadName, campaignName, and accountName follow their ids. In data, a field marked ? is only on some events of that type, and a field not listed is missing or null. The examples are full request bodies, like the one in What Needle sends, with made-up values.
lead_createdA lead was created, from the app, the API, MCP, an import, or a direct message to someone who was not a lead yet.
Set: leadId.
data: profile?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_created",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_created",
"label": "Lead created",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"profile": {
"name": "Jane Doe",
"identity": "jane-doe",
"url": "https://www.linkedin.com/in/jane-doe"
}
}
}
}lead_updatedA lead's details or handles changed; data.changes lists each changed field.
Set: leadId.
data: changes
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_updated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_updated",
"label": "Lead updated",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"changes": {
"jobTitle": {
"from": "Engineer",
"to": "Head of Engineering"
},
"linkedin": {
"from": null,
"to": "jane-doe"
}
}
}
}
}lead_deletedA lead was deleted. Its live campaigns stop with exitReason lead_deleted.
Set: leadId.
data: profile?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_deleted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_deleted",
"label": "Lead deleted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"profile": {
"name": "Jane Doe",
"identity": "jane-doe",
"url": "https://www.linkedin.com/in/jane-doe"
}
}
}
}lead_enrolledA lead was added to a campaign.
Set: leadId, campaignId, enrollmentId.
data: null
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_enrolled",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_enrolled",
"label": "Lead added",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": null
}
}lead_skippedA lead was not added to a campaign; data.skipReason says why.
Set: leadId, campaignId. leadId is null when skipReason is lead_not_found.
data: skipReason, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_skipped",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_skipped",
"label": "Lead skipped",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"skipReason": "recently_contacted",
"message": "Contacted by your workspace within the last 30 days"
}
}
}message_generatedAI wrote a message for a step.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: text
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "message_generated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "message_generated",
"label": "AI message written",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"text": "Hi Jane, open to a quick chat?"
}
}
}condition_evaluatedA check in the sequence was evaluated.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, properties.branch, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "condition_evaluated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "condition_evaluated",
"label": "Check evaluated",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_profile_view",
"properties": {
"branch": "no"
}
}
}
}task_heldA step is waiting for approval.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, text, subject?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_held",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_held",
"label": "Held for approval",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_message",
"text": "Hi Jane, open to a quick chat?",
"subject": null
}
}
}task_approvedA held step was approved.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, text, properties.edited
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_approved",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_approved",
"label": "Message approved",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_message",
"text": "Hi Jane, open to a quick chat?",
"properties": {
"edited": "true"
}
}
}
}task_skippedA step was skipped; data.skipReason says why.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, skipReason
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_skipped",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_skipped",
"label": "Step skipped",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_invitation",
"skipReason": "already_invited"
}
}
}task_cancelledA step was cancelled before it ran.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, message
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_cancelled",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_cancelled",
"label": "Step cancelled",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_message",
"message": "The lead is no longer active in this campaign (stopped)"
}
}
}task_failedA step failed; data.errorKind says why.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId.
data: action, skipReason?, errorKind?, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_failed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "task_failed",
"label": "Step failed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_message",
"skipReason": "not_first_degree"
}
}
}enrollment_waitingThe sequence is waiting, for example for a reply.
Set: leadId, campaignId, enrollmentId, channel, nodeId.
data: properties.waitingFor, properties.timeoutAt
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_waiting",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_waiting",
"label": "Sequence waiting",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"properties": {
"waitingFor": "linkedin_invite_accepted",
"timeoutAt": "2026-01-15T12:00:00.000Z"
}
}
}
}enrollment_completedThe lead reached the end of the sequence.
Set: leadId, campaignId, enrollmentId.
data: exitReason
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_completed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_completed",
"label": "Sequence finished",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"exitReason": "finished"
}
}
}enrollment_stoppedThe sequence stopped early; data.exitReason says why.
Set: leadId, campaignId, enrollmentId.
data: exitReason, suppressionReason?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_stopped",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "enrollment_stopped",
"label": "Sequence stopped",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"exitReason": "replied"
}
}
}lead_suppressedA lead matched a suppression.
Set: leadId, campaignId, enrollmentId, channel.
data: suppressionReason, keyword
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_suppressed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "lead_suppressed",
"label": "Lead suppressed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"suppressionReason": "not_interested",
"keyword": "not interested"
}
}
}campaign_status_changedA campaign's status changed, for example it was started or paused.
Set: campaignId.
data: message
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "campaign_status_changed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "campaign_status_changed",
"label": "Campaign status changed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"message": "draft -> active"
}
}
}campaign_updatedA campaign's name, sequence, schedule, limits or suppression policy was edited; data.changedFields lists which.
Set: campaignId.
data: changedFields
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "campaign_updated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "campaign_updated",
"label": "Campaign edited",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"changedFields": [
"graph",
"schedule"
]
}
}
}account_connectedA LinkedIn or Instagram account was connected to the workspace for the first time, or again after it was deleted.
Set: connectedAccountId, channel.
data: null
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_connected",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_connected",
"label": "Account connected",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": null
}
}account_reconnectedA disconnected account works again, because a member signed in to it again or LinkedIn or Instagram reports it healthy.
Set: connectedAccountId, channel.
data: null
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_reconnected",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_reconnected",
"label": "Account reconnected",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": null
}
}account_deletedA connected account was deleted.
Set: connectedAccountId, channel.
data: null
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_deleted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_deleted",
"label": "Account deleted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": null
}
}account_pausedA connected account was paused, by its owner or after hitting a limit (data.errorKind).
Set: connectedAccountId, channel.
data: errorKind?, message, properties.pausedUntil?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_paused",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_paused",
"label": "Account paused",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"errorKind": "rate_limited",
"message": "Rate limited by the provider",
"properties": {
"pausedUntil": "2026-01-01T12:15:00.000Z"
}
}
}
}account_resumedA paused connected account was resumed, by its owner or when billing was restored.
Set: connectedAccountId, channel.
data: message
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_resumed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_resumed",
"label": "Account resumed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"message": "Resumed by hand"
}
}
}account_disconnectedA connected account stopped working: it needs signing in again (data.errorKind is auth_required) or LinkedIn or Instagram disconnected it (disconnected). Its campaigns wait until it is reconnected.
Set: connectedAccountId, channel.
data: errorKind
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_disconnected",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_disconnected",
"label": "Account disconnected",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"errorKind": "auth_required"
}
}
}account_suspendedA connected account was signed out and stopped, because the workspace's billing lapsed or its owner was removed from the workspace (data.message). It has to be connected again to be used.
Set: connectedAccountId, channel.
data: message
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_suspended",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_suspended",
"label": "Account suspended",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"message": "billing"
}
}
}account_limits_updatedA connected account's usage limits were changed; data.changes lists each limit.
Set: connectedAccountId, channel.
data: changes
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_limits_updated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_limits_updated",
"label": "Account limits changed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"changes": {
"linkedin_invitation.day": {
"from": "20",
"to": "25"
},
"linkedin_invitation.week": {
"from": "100",
"to": "120"
}
}
}
}
}account_access_grantedA member (data.member) was allowed to use a connected account.
Set: connectedAccountId, channel.
data: member
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_access_granted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_access_granted",
"label": "Account access granted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
}
}
}
}account_access_revokedA member (data.member) can no longer use a connected account. Campaigns they started with it pause.
Set: connectedAccountId, channel.
data: member
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_access_revoked",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_access_revoked",
"label": "Account access removed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
}
}
}
}account_sharing_changedA connected account was shared with the whole workspace, or stopped being shared.
Set: connectedAccountId, channel.
data: changes
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_sharing_changed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "account_sharing_changed",
"label": "Account sharing changed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"changes": {
"sharedWithWorkspace": {
"from": "false",
"to": "true"
}
}
}
}
}member_invitedSomeone was invited to the workspace.
Set: .
data: email, role
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_invited",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_invited",
"label": "Member invited",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"email": "ada@example.com",
"role": "member"
}
}
}member_invitation_revokedAn invitation to the workspace was withdrawn.
Set: .
data: email, role
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_invitation_revoked",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_invitation_revoked",
"label": "Invitation revoked",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"email": "ada@example.com",
"role": "member"
}
}
}member_joinedSomeone accepted an invitation and joined.
Set: .
data: member, role
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_joined",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_joined",
"label": "Member joined",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
},
"role": "member"
}
}
}member_role_changedA member's role changed.
Set: .
data: member, changes
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_role_changed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_role_changed",
"label": "Member role changed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
},
"changes": {
"role": {
"from": "member",
"to": "admin"
}
}
}
}
}member_removedAn admin removed a member. Their accounts are suspended and their campaigns pause.
Set: .
data: member, role
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_removed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_removed",
"label": "Member removed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
},
"role": "member"
}
}
}member_leftA member deleted their Needle account.
Set: .
data: member, role
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_left",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "member_left",
"label": "Member left",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"member": {
"userId": "00000000-0000-0000-0000-000000000006",
"name": "Ada Lovelace"
},
"role": "member"
}
}
}api_key_createdAn API key was created.
Set: .
data: apiKey
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_created",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_created",
"label": "API key created",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"apiKey": {
"id": "00000000-0000-0000-0000-000000000007",
"name": "CRM sync"
}
}
}
}api_key_revokedAn API key was disabled.
Set: .
data: apiKey
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_revoked",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_revoked",
"label": "API key disabled",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"apiKey": {
"id": "00000000-0000-0000-0000-000000000007",
"name": "CRM sync"
}
}
}
}api_key_enabledA disabled API key was enabled again.
Set: .
data: apiKey
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_enabled",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_enabled",
"label": "API key enabled",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"apiKey": {
"id": "00000000-0000-0000-0000-000000000007",
"name": "CRM sync"
}
}
}
}api_key_deletedAn API key was deleted.
Set: .
data: apiKey
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_deleted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "api_key_deleted",
"label": "API key deleted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"apiKey": {
"id": "00000000-0000-0000-0000-000000000007",
"name": "CRM sync"
}
}
}
}webhook_createdA webhook was added.
Set: .
data: webhook
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_created",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_created",
"label": "Webhook added",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"webhook": {
"id": "00000000-0000-0000-0000-000000000008",
"host": "hooks.example.com"
}
}
}
}webhook_updatedA webhook's URL or headers changed; data.changedFields lists which.
Set: .
data: webhook, changedFields
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_updated",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_updated",
"label": "Webhook changed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"webhook": {
"id": "00000000-0000-0000-0000-000000000008",
"host": "hooks.example.com"
},
"changedFields": [
"url",
"headers"
]
}
}
}webhook_deletedA webhook was removed.
Set: .
data: webhook
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_deleted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "webhook_deleted",
"label": "Webhook removed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"webhook": {
"id": "00000000-0000-0000-0000-000000000008",
"host": "hooks.example.com"
}
}
}
}suppression_addedA lead or company was added to the do-not-contact list by a member or through the API.
Set: leadId. leadId is null for a company-wide entry, which sets data.companyDomain instead.
data: suppressionId, suppressionReason, companyDomain?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "suppression_added",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "suppression_added",
"label": "Added to do-not-contact list",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"suppressionId": "00000000-0000-0000-0000-000000000009",
"suppressionReason": "existing_customer"
}
}
}suppression_removedAn entry was removed from the do-not-contact list.
Set: leadId. leadId is null for a company-wide entry, which sets data.companyDomain instead.
data: suppressionId, suppressionReason, companyDomain?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "suppression_removed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "suppression_removed",
"label": "Removed from do-not-contact list",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": null,
"nodeId": null,
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": null,
"accountName": null,
"actorUserId": null,
"actorName": null,
"data": {
"suppressionId": "00000000-0000-0000-0000-000000000009",
"suppressionReason": "existing_customer"
}
}
}linkedin_profile_visitedA LinkedIn profile was visited.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, profile?, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_profile_visited",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_profile_visited",
"label": "Profile visited",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_profile_view",
"text": null,
"profile": {
"name": "Jane Doe",
"identity": "jane-doe",
"url": null,
"imageUrl": null
}
}
}
}linkedin_invite_sentA LinkedIn connection request was sent.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, text?, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_sent",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_sent",
"label": "Connection request sent",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_invitation",
"text": "Hi Jane, would love to connect."
}
}
}linkedin_invite_withdrawnA LinkedIn connection request was withdrawn.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_withdrawn",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_withdrawn",
"label": "Connection request withdrawn",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_cancel_invitation",
"text": null
}
}
}linkedin_message_sentA LinkedIn message was sent, through Needle or by the account owner in LinkedIn (data.sentOutsideNeedle).
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, text, subject?, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_sent",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_sent",
"label": "Message sent",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_message",
"text": "Hi Jane, open to a quick chat?",
"subject": null
}
}
}linkedin_follow_sentA LinkedIn profile was followed.
Not sent yet.
linkedin_unfollowedA LinkedIn profile was unfollowed.
Not sent yet.
linkedin_invite_acceptedA LinkedIn connection request was accepted.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel. leadId is set too when the person is one of your leads, and campaignId, enrollmentId, and nodeId when they are still in one of your campaigns.
data: profile?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_accepted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_invite_accepted",
"label": "Connection request accepted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"profile": {
"identity": "jane-doe",
"url": "https://www.linkedin.com/in/jane-doe"
}
}
}
}linkedin_message_receivedA LinkedIn reply was received.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel. leadId is set too when the person is one of your leads, and campaignId, enrollmentId, and nodeId when they are still in one of your campaigns.
data: text, profile?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_received",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_message_received",
"label": "Reply received",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"text": "Thanks, happy to chat next week.",
"profile": {
"name": "Jane Doe",
"identity": "jane-doe",
"url": "https://www.linkedin.com/in/jane-doe"
}
}
}
}linkedin_post_commentedA comment was posted on LinkedIn.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action, text
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_post_commented",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_post_commented",
"label": "Comment posted",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_comment",
"text": "Great point on pricing."
}
}
}linkedin_post_reactedA reaction was added to a LinkedIn post.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_post_reacted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "linkedin_post_reacted",
"label": "Post reaction added",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "linkedin",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "linkedin_reaction"
}
}
}instagram_message_sentAn Instagram message was sent, through Needle or by the account owner in Instagram (data.sentOutsideNeedle).
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, text, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_sent",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_sent",
"label": "Message sent",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_message",
"text": "Hi Jane, love your shop!"
}
}
}instagram_profile_visitedAn Instagram profile was visited.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, profile?, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_profile_visited",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_profile_visited",
"label": "Profile visited",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_profile_view",
"text": null,
"profile": {
"name": "Jane Doe",
"identity": "janedoe",
"url": "https://www.instagram.com/janedoe/",
"imageUrl": null
}
}
}
}instagram_follow_sentAn Instagram profile was followed.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_follow_sent",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_follow_sent",
"label": "Followed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_follow",
"text": null
}
}
}instagram_unfollowedAn Instagram profile was unfollowed.
Account-sensitive. See Who sees an event.
Set: leadId, campaignId, enrollmentId, connectedAccountId, channel, nodeId. From the API or MCP, campaignId, enrollmentId, and nodeId are null, and leadId is set only when the action was aimed at a lead.
data: action, message?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_unfollowed",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_unfollowed",
"label": "Unfollowed",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": "step_1",
"leadId": "00000000-0000-0000-0000-000000000002",
"leadName": "Jane Doe",
"leadImageUrl": null,
"campaignId": "00000000-0000-0000-0000-000000000003",
"campaignName": "Example campaign",
"enrollmentId": "00000000-0000-0000-0000-000000000004",
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_unfollow",
"text": null
}
}
}instagram_message_receivedAn Instagram reply was received.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel. leadId is set too when the person is one of your leads, and campaignId, enrollmentId, and nodeId when they are still in one of your campaigns.
data: text, profile?
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_received",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_received",
"label": "Reply received",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"text": "Sounds good!",
"profile": {
"name": "Jane Doe",
"identity": "janedoe",
"url": "https://www.instagram.com/janedoe"
}
}
}
}instagram_post_commentedA comment was posted on Instagram.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action, text
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_commented",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_commented",
"label": "Commented on a post",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_comment",
"text": "Love this."
}
}
}instagram_post_reactedAn Instagram post was liked.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_reacted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_reacted",
"label": "Liked a post",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_reaction"
}
}
}instagram_message_reactedA reaction was added to an Instagram message.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_reacted",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_message_reacted",
"label": "Reacted to a message",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_reaction"
}
}
}instagram_post_createdAn Instagram post was published.
Account-sensitive. See Who sees an event.
Set: connectedAccountId, channel.
data: action, text
{
"version": "v1",
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_created",
"timestamp": "2026-01-01T12:00:00.000Z",
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"type": "instagram_post_created",
"label": "Post published",
"occurredAt": "2026-01-01T12:00:00.000Z",
"channel": "instagram",
"nodeId": null,
"leadId": null,
"leadName": null,
"leadImageUrl": null,
"campaignId": null,
"campaignName": null,
"enrollmentId": null,
"connectedAccountId": "00000000-0000-0000-0000-000000000005",
"accountName": "John Doe",
"actorUserId": null,
"actorName": null,
"data": {
"action": "instagram_post",
"text": "New office, same team."
}
}
}Every body has "version": "v1". Within v1, new event types and new fields can be added, but fields are not removed or renamed. Ignore types and fields you do not know.
Search documentation, API reference, and MCP tools
We use cookies to enhance your experience on Needle and keep your data secure. Privacy Policy