Skip to main content
POST
Add Webhook

Limits and conflicts

A workspace holds at most 200 webhooks, and a targetUrl can only be registered once. Both limits answer 409, with a JSON body whose error field tells them apart:
Uniqueness is on targetUrl alone, regardless of type and campaignId. The same URL cannot be registered twice to subscribe to two event types — either register it once without a type (it then receives every event, and you filter on your side), or give each subscription its own URL.

Disabled webhooks still count toward the cap

When a delivery fails in a way that says the destination is gone — your endpoint answers 404 or 410, or its host does not resolve — lemlist disables the webhook instead of deleting it, and notifies its owner. Get Many Webhooks keeps returning it, carrying disabled: true, disabledReason: "deliveryError", disabledAt and lastErrorStatus. A disabled webhook stops firing but keeps its slot, and nothing purges it. A workspace showing a handful of live webhooks can therefore be refused a new one. When you check the remaining room, count every entry GET /hooks returns, not just the active ones, and delete those you no longer need.

Available event types

When creating a webhook, you can subscribe to specific events using the type field. Events are organized by category below.

Lead state groups

These aggregate multiple activity types into a single lead-state change event.

Email activities

Unsubscribe activities

Since March 30, 2026, a contact unsubscribing emits entityUnsubscribed (whole contact) or variableUnsubscribed (single variable) instead of emailsUnsubscribed. If your integration listens to emailsUnsubscribed, also subscribe to entityUnsubscribed and variableUnsubscribed to keep receiving unsubscribe events.

LinkedIn activities

WhatsApp activities

SMS activities

Call activities

API activities

Manual activities

Task activities

Workspace activities

Enrichment

Contact sourcing

The payload of both is the same shape Get Contact Sourcing Run answers with, under a data key.
Subscribe to contactSourcingFailed as well as contactSourcingDone: a run that fails never emits the done event, so an integration listening only for the latter waits for a result that is not coming.

Inbox activities

Signal Agents

Deliverability hub

Deprecated events

These events have been removed from the API. Use the replacements below.

Verifying webhook authenticity

You can pass an optional secret in the request body when creating the webhook. It works like a shared password between lemlist and your endpoint:
  • Stored encrypted at rest.
  • Never returned by GET /hooks or any other endpoint.
  • Immutable — it cannot be changed after creation. To rotate it, delete the webhook and create a new one.
  • Sent back to your endpoint as a secret field in the JSON body of every webhook call, so you can verify the request originated from lemlist.

Webhook payload

Each event is delivered as a POST to your targetUrl with a JSON body that mirrors the underlying activity record. Common fields:
stepId identifies the step itself, while sequenceStep is a position that shifts when a sequence’s steps are reordered — prefer stepId when you store a reference. Both are sent: sequenceStep is unchanged. stepId is present on every activity created from now on, and older activities gain it progressively as historical records are backfilled.

Email recipients (to / cc / bcc)

Email events (emailsSent, emailsReplied, emailsBounced) carry the full recipient lists as arrays of {address, name}. Addresses are lowercased. Fields are omitted when empty.
  • to — primary recipient(s). For outbound sends, this is the lead. For inbound replies, this is the mailbox owner; multi-recipient to lines (e.g. reply-all where the lead manually added people) are preserved.
  • cc — explicit CC recipients on the email.
  • bcc — only present for outbound emailsSent events when the sender has a hidden BCC configured in Settings → Integrations (users.lemlist.bcc). Inbound BCC is never visible because SMTP strips it for non-BCC’d recipients.

Third-party reply flag

When a reply on a thread comes from an address that does not match the original lead’s known contact emails, lemlist attributes the reply to the third-party sender rather than to the lead, and the event carries an extra flag:
Third-party reply payloads omit campaignId, leadId, and sequenceId (since the reply is no longer attached to the original campaign flow). Use the flag to route these events differently if needed.

Examples

Tip: You can include an optional zapId if you use Zapier to track the webhook mapping on your side.

Authorizations

Authorization
string
header
required

Basic authentication header of the form Basic <encoded-value>, where <encoded-value> is the base64-encoded string username:password.

Query Parameters

campaignId
string

Webhook for specific campaign

isFirst
boolean

Webhook for first activity only

zapId
string

Zapier ID

Body

application/json
targetUrl
string<uri>
required

The URL that will receive webhook POST requests.

type
enum<string>

Optional event type to subscribe to. When omitted, all events are sent. See the full categorized list in the endpoint documentation.

Available options:
contacted,
hooked,
attracted,
warmed,
interested,
notInterested,
emailsSent,
emailsOpened,
emailsClicked,
emailsReplied,
emailsBounced,
emailsFailed,
emailsInterested,
emailsNotInterested,
emailsUnsubscribed,
entityUnsubscribed,
variableUnsubscribed,
linkedinSent,
linkedinOpened,
linkedinReplied,
linkedinInterested,
linkedinNotInterested,
linkedinSendFailed,
linkedinVisitDone,
linkedinVisitFailed,
linkedinFollowDone,
linkedinFollowFailed,
linkedinFollowSkipped,
linkedinInviteDone,
linkedinInviteFailed,
linkedinInviteAccepted,
linkedinEndorseDone,
linkedinEndorseFailed,
linkedinEndorseSkipped,
linkedinVoiceNoteDone,
linkedinVoiceNoteFailed,
linkedinLikeLastPostDone,
linkedinLikeLastPostNoPost,
linkedinLikeLastPostFailed,
linkedinWithdrawInvitationDone,
linkedinWithdrawInvitationFailed,
whatsappMessageSent,
whatsappMessageDelivered,
whatsappMessageOpened,
whatsappReplied,
whatsappMessageFailed,
smsSent,
smsDelivered,
smsReplied,
smsFailed,
aircallCreated,
aircallEnded,
aircallDone,
aircallInterested,
aircallNotInterested,
apiDone,
apiInterested,
apiNotInterested,
apiFailed,
manualInterested,
manualNotInterested,
paused,
resumed,
stopped,
campaignComplete,
customDomainErrors,
connectionIssue,
sendLimitReached,
lemwarmPaused,
annotated,
enrichmentDone,
enrichmentError,
callRecordingDone,
callTranscriptDone,
inboxLabelUpdated,
signalRegistered,
deliverabilityAlertTriggered,
contactSourcingDone,
contactSourcingFailed
secret
string

Optional shared secret. Stored encrypted, never returned by GET, and immutable once set. Sent back to your endpoint as a secret field in the body of every webhook call so you can verify the request originated from lemlist.

Response

Success

_id
string

Unique identifier for the webhook

targetUrl
string

The URL where the webhook will send data

createdAt
string<date-time>

Timestamp when the webhook was created

type
string

Type of webhook event