> ## Documentation Index
> Fetch the complete documentation index at: https://developer.lemlist.com/llms.txt
> Use this file to discover all available pages before exploring further.

> Creates a webhook that receives real-time POST callbacks for selected events.

# Add Webhook

export const SnippetObjectReference = ({objectName, objectPath = null}) => {
  const lowerCaseObjectName = objectName.toLowerCase();
  if (lowerCaseObjectName === 'lead' || lowerCaseObjectName === 'leads') {
    return <Note>
        This endpoint uses the <a href={`/api-reference/objects-definitions/${objectPath}`}>{objectName} object</a>. Make sure to also check the <a href={`/api-reference/objects-definitions/${lowerCaseObjectName === 'lead' ? 'contact' : 'lead'}`}>{lowerCaseObjectName === 'lead' ? 'Contact' : 'Lead'} object</a> to understand the distinction between the two.
      </Note>;
  }
  return <Note>
      This endpoint uses the <a href={`/api-reference/objects-definitions/${objectPath}`}>{objectName} object</a>.
    </Note>;
};

<SnippetObjectReference objectName="Webhook" objectPath="webhook" />

## 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.

| Event           | Description                                                       |
| --------------- | ----------------------------------------------------------------- |
| `contacted`     | Lead was contacted (email sent, LinkedIn message, API call, etc.) |
| `hooked`        | Lead opened a message (email, LinkedIn, WhatsApp)                 |
| `attracted`     | Lead clicked a link or accepted a LinkedIn invite                 |
| `warmed`        | Lead replied (email, LinkedIn, WhatsApp, SMS)                     |
| `interested`    | Lead marked as interested                                         |
| `notInterested` | Lead marked as not interested                                     |

### Email activities

| Event                 | Description                             |
| --------------------- | --------------------------------------- |
| `emailsSent`          | Email sent                              |
| `emailsOpened`        | Email opened                            |
| `emailsClicked`       | Link clicked in email                   |
| `emailsReplied`       | Email replied                           |
| `emailsBounced`       | Email bounced                           |
| `emailsFailed`        | Email failed to send                    |
| `emailsInterested`    | Lead marked as interested via email     |
| `emailsNotInterested` | Lead marked as not interested via email |
| `emailsUnsubscribed`  | Lead unsubscribed via email             |

### LinkedIn activities

| Event                              | Description                                |
| ---------------------------------- | ------------------------------------------ |
| `linkedinSent`                     | LinkedIn message sent                      |
| `linkedinOpened`                   | LinkedIn message opened                    |
| `linkedinReplied`                  | LinkedIn message replied                   |
| `linkedinInterested`               | Lead marked as interested via LinkedIn     |
| `linkedinNotInterested`            | Lead marked as not interested via LinkedIn |
| `linkedinSendFailed`               | LinkedIn message failed to send            |
| `linkedinVisitDone`                | LinkedIn profile visit completed           |
| `linkedinVisitFailed`              | LinkedIn profile visit failed              |
| `linkedinFollowDone`               | LinkedIn follow completed                  |
| `linkedinFollowFailed`             | LinkedIn follow failed                     |
| `linkedinFollowSkipped`            | LinkedIn follow skipped                    |
| `linkedinInviteDone`               | LinkedIn invite sent                       |
| `linkedinInviteFailed`             | LinkedIn invite failed                     |
| `linkedinInviteAccepted`           | LinkedIn invite accepted                   |
| `linkedinEndorseDone`              | LinkedIn endorsement completed             |
| `linkedinEndorseFailed`            | LinkedIn endorsement failed                |
| `linkedinEndorseSkipped`           | LinkedIn endorsement skipped               |
| `linkedinVoiceNoteDone`            | LinkedIn voice note sent                   |
| `linkedinVoiceNoteFailed`          | LinkedIn voice note failed                 |
| `linkedinLikeLastPostDone`         | LinkedIn like last post completed          |
| `linkedinLikeLastPostNoPost`       | LinkedIn like last post — no post found    |
| `linkedinLikeLastPostFailed`       | LinkedIn like last post failed             |
| `linkedinWithdrawInvitationDone`   | LinkedIn invite withdrawn                  |
| `linkedinWithdrawInvitationFailed` | LinkedIn invite withdrawal failed          |

### WhatsApp activities

| Event                      | Description                |
| -------------------------- | -------------------------- |
| `whatsappMessageSent`      | WhatsApp message sent      |
| `whatsappMessageDelivered` | WhatsApp message delivered |
| `whatsappMessageOpened`    | WhatsApp message opened    |
| `whatsappReplied`          | WhatsApp message replied   |
| `whatsappMessageFailed`    | WhatsApp message failed    |

### SMS activities

| Event          | Description   |
| -------------- | ------------- |
| `smsSent`      | SMS sent      |
| `smsDelivered` | SMS delivered |
| `smsReplied`   | SMS replied   |
| `smsFailed`    | SMS failed    |

### Call activities

| Event                  | Description                            |
| ---------------------- | -------------------------------------- |
| `aircallCreated`       | Call created                           |
| `aircallEnded`         | Call ended                             |
| `aircallDone`          | Call task completed                    |
| `aircallInterested`    | Lead marked as interested via call     |
| `aircallNotInterested` | Lead marked as not interested via call |
| `callRecordingDone`    | Call recording ready                   |
| `callTranscriptDone`   | Call transcript ready                  |

### API activities

| Event              | Description                           |
| ------------------ | ------------------------------------- |
| `apiDone`          | API step executed                     |
| `apiInterested`    | Lead marked as interested via API     |
| `apiNotInterested` | Lead marked as not interested via API |
| `apiFailed`        | API step failed                       |

### Manual activities

| Event                 | Description                            |
| --------------------- | -------------------------------------- |
| `manualInterested`    | Lead marked as interested manually     |
| `manualNotInterested` | Lead marked as not interested manually |

### Task activities

| Event       | Description    |
| ----------- | -------------- |
| `annotated` | Lead annotated |

### Workspace activities

| Event                | Description                    |
| -------------------- | ------------------------------ |
| `paused`             | Lead paused                    |
| `resumed`            | Lead resumed                   |
| `stopped`            | Lead stopped                   |
| `campaignComplete`   | Campaign completed             |
| `customDomainErrors` | Custom domain error detected   |
| `connectionIssue`    | Email account connection issue |
| `sendLimitReached`   | Daily send limit reached       |
| `lemwarmPaused`      | Lemwarm paused                 |

### Enrichment

| Event             | Description          |
| ----------------- | -------------------- |
| `enrichmentDone`  | Enrichment completed |
| `enrichmentError` | Enrichment failed    |

### Inbox activities

| Event               | Description                      |
| ------------------- | -------------------------------- |
| `inboxLabelUpdated` | Inbox conversation label changed |

### Signal Agents

| Event              | Description                           |
| ------------------ | ------------------------------------- |
| `signalRegistered` | New signal detected by a Signal Agent |

### Deliverability hub

| Event                          | Description                    |
| ------------------------------ | ------------------------------ |
| `deliverabilityAlertTriggered` | Deliverability alert triggered |

### Deprecated events

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

| Removed event       | Replacement                                    |
| ------------------- | ---------------------------------------------- |
| `skipped`           | No direct replacement                          |
| `emailsSendFailed`  | Use `emailsFailed` instead                     |
| `opportunitiesDone` | Use `annotated` or task-level webhooks instead |

## 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:

| Field                                         | Type     | Description                                      |
| --------------------------------------------- | -------- | ------------------------------------------------ |
| `_id`                                         | string   | Unique activity identifier (`act_…`)             |
| `type`                                        | string   | Event type (e.g. `emailsSent`, `emailsReplied`)  |
| `teamId`                                      | string   | Team the activity belongs to                     |
| `createdAt`                                   | ISO date | When the activity happened                       |
| `campaignId`                                  | string   | Source campaign (absent for non-campaign events) |
| `campaignName`                                | string   | Campaign display name                            |
| `sequenceId`                                  | string   | Sequence the task belonged to                    |
| `sequenceStep`                                | number   | 0-based step index in the sequence               |
| `leadId`                                      | string   | Lead targeted by the activity                    |
| `leadEmail`, `leadFirstName`, `leadLastName`  | string   | Denormalized lead identity                       |
| `sendUserId`, `sendUserEmail`, `sendUserName` | string   | Sender (lemlist user) identity                   |
| `subject`                                     | string   | Email subject (email events only)                |
| `secret`                                      | string   | Echoed back if a `secret` was set on the webhook |

### 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.

```json theme={"theme":"dracula"}
{
  "type": "emailsSent",
  "to":  [{ "address": "lead@example.com", "name": "Alice Doe" }],
  "cc":  [{ "address": "manager@example.com", "name": "" }],
  "bcc": [{ "address": "archive@crm.io", "name": "" }]
}
```

* `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:

```json theme={"theme":"dracula"}
{
  "type": "emailsReplied",
  "isThirdPartyReply": true
}
```

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

<CodeGroup>
  ```json all events theme={"theme":"dracula"}
  {
  	"targetUrl": "https://webhook.site/your-id"
  }
  ```

  ```json specific event and campaign theme={"theme":"dracula"}
  {
  	"targetUrl": "https://webhook.site/your-id",
  	"type": "linkedinInterested",
  	"campaignId": "cam_A1B2C3D4E5F6G7H8I9",
  	"isFirst": true
  }
  ```

  ```json whatsapp events theme={"theme":"dracula"}
  {
  	"targetUrl": "https://webhook.site/your-id",
  	"type": "whatsappReplied"
  }
  ```

  ````json signal agent signals theme={"theme":"dracula"}
  {
  	"targetUrl": "https://webhook.site/your-id",
  	"type": "signalRegistered"
  ```json with shared secret
  {
  	"targetUrl": "https://webhook.site/your-id",
  	"secret": "s3cret-shared-with-my-endpoint"
  }
  ````
</CodeGroup>

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


## OpenAPI

````yaml post /hooks
openapi: 3.0.0
info:
  title: lemlist API
  version: 1.0.0
  description: >-
    Welcome to the lemlist Developer Documentation.


    lemlist is very customizable and open. You'll find on this page all the API
    and integration you can do with lemlist.


    # Rate Limit


    lemlist's API rate limits requests in order to prevent abuse and overload of
    our services.  

    Rate limits are applied on all routes and per API key performing the
    request.  

    The rate limits are **20** requests per **2** seconds.  

    The response provides any information you may need about it:


    | Header | Description |

    | --- | --- |

    | Retry-After | The number of seconds in which you can retry |

    | X-RateLimit-Limit | The maximum requests in that time |

    | X-RateLimit-Remaining | The number of remaining requests you can make |

    | X-RateLimit-Reset | The date when the rate limit will reset |


    _Example of values for the rate limit headers_


    ``` json

    {
        "Retry-After": 2,
        "X-RateLimit-Limit": 20,
        "X-RateLimit-Remaining": 7,
        "X-RateLimit-Reset" : "Tue Feb 16 2021 09:02:42 GMT+0100 (Central European Standard Time)"
    }

     ```

    # Definitions


    ## Team


    A team is the entity of lemlist that can handle users and billing.


    ## Credits


    Credits are the coins a team uses to enrich emails, LinkedIn URLs, etc. via
    the enrich route. Each enrichment feature needs a certain amount of credits
    to run.


    ## User


    You use a user account to connect to lemlist and send messages via the
    connected emails or LinkedIn account.


    ## Campaign


    A campaign is the entity to automate outreach. A campaign has multiple
    sequences composed of steps.


    ## Lead


    A lead is a person that you try to contact via a campaign.


    ## Activity


    An activity is the history of all the steps.


    ## Unsubscribe


    An unsubscribe occurs when a person decides they don't want to receive
    emails from you anymore.


    # Authentication


    All API routes use the dedicated subdomain `api.lemlist.com`.


    lemlist uses API keys to allow access to the API. You can get your lemlist
    API key at our [integration
    page](https://app.lemlist.com/settings/integrations).


    You need to add the `Authorization` header using the `Basic` authentication
    type. `login:password` **where the login is always empty and the password is
    the API key**.


    ⚠️ **Don't forget to add the semicolon (**`:`**) before your API key in curl
    command.**


    > To authorize, use this code: 
      

    ``` shell

    curl https://api.lemlist.com/api/team \
      --user ":YourApiKey"

     ```

    **Make sure to replace** **`YourApiKey`** **with your API key.**


    # Give feedback


    If you want to report a bug, ask for data, or share with us a use case,
    please fill this [form](https://lemlist.typeform.com/to/mfVlkyGf). It will
    help us centralize your needs!
servers:
  - url: https://api.lemlist.com/api
security:
  - basicAuth: []
paths:
  /hooks:
    post:
      tags:
        - Webhooks
      summary: Add Webhook
      parameters:
        - name: campaignId
          in: query
          required: false
          description: Webhook for specific campaign
          example: cam_123
          schema:
            type: string
        - name: isFirst
          in: query
          required: false
          description: Webhook for first activity only
          example: 'true'
          schema:
            type: boolean
        - name: zapId
          in: query
          required: false
          description: Zapier ID
          example: '123456789'
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                targetUrl:
                  type: string
                  format: uri
                  description: The URL that will receive webhook POST requests.
                type:
                  type: string
                  description: >-
                    Optional event type to subscribe to. When omitted, all
                    events are sent. See the full categorized list in the
                    endpoint documentation.
                  enum:
                    - contacted
                    - hooked
                    - attracted
                    - warmed
                    - interested
                    - notInterested
                    - emailsSent
                    - emailsOpened
                    - emailsClicked
                    - emailsReplied
                    - emailsBounced
                    - emailsFailed
                    - emailsInterested
                    - emailsNotInterested
                    - emailsUnsubscribed
                    - 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
                secret:
                  type: string
                  description: >-
                    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.
              required:
                - targetUrl
            example:
              targetUrl: https://webhook.site/00000000-0000-0000-0000-000000000000
              type: linkedinInterested
              secret: s3cret-shared-with-my-endpoint
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  _id:
                    type: string
                    description: Unique identifier for the webhook
                  targetUrl:
                    type: string
                    description: The URL where the webhook will send data
                  createdAt:
                    type: string
                    format: date-time
                    description: Timestamp when the webhook was created
                  type:
                    type: string
                    description: Type of webhook event
              example:
                _id: hoo_GvYkkWIcdPf2WsBDY
                targetUrl: https://n8n.example.com/webhook/lemlist-webhook-surprise
                createdAt: '2025-10-29T00:47:42.035Z'
                type: linkedinInterested
        '400':
          description: Bad team
          content:
            text/plain:
              example: Bad team
        '401':
          description: Unauthorized
        '404':
          description: Webhook not found
          content:
            text/plain:
              example: Webhook not found
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

````