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

# Create Subscription

> Create up to 25 webhook subscriptions per request. Specify the entity type, entity IDs, signal types to monitor, and your HTTPS webhook endpoint URL.

Send a single request to subscribe one or more contacts or companies to real-time signal notifications. Each subscription links an entity to a webhook URL and the set of signal types you want to receive. Lusha delivers a signed JSON payload to your endpoint whenever a matching signal fires.

<Warning>
  Your account must have a webhook secret before deliveries can be received. Generate one by calling `POST /api/account/secret/regenerate` and store it securely - it is shown only once.
</Warning>

**Endpoint:** `POST https://api.lusha.com/api/subscriptions`

<Note>
  You can create up to 25 subscriptions per request.
</Note>

## Request body

<ParamField body="defaults" type="object" required>
  Default values applied to every subscription in the request, unless overridden per item.

  <Expandable title="properties">
    <ParamField body="defaults.url" type="string" required>
      The HTTPS URL where Lusha will POST signal payloads. HTTP URLs are not accepted in production. Maximum length 2048 characters.
    </ParamField>

    <ParamField body="defaults.entityType" type="string">
      Default entity type for all subscriptions in the request. Accepted values: `contact`, `company`. Can be overridden per subscription item.
    </ParamField>

    <ParamField body="defaults.signalTypes" type="string[]">
      Default signal type keys for all subscriptions in the request. Available signals depend on entity type - see [Contact Signal Types](/api-reference/signals/contact-signal-types) or [Company Signal Types](/api-reference/signals/company-signal-types) for the full list. Can be overridden per subscription item.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="name" type="string">
  Default subscription name prefix, applied unless a subscription item specifies its own `name`. Maximum 100 characters.
</ParamField>

<ParamField body="subscriptions" type="object[]" required>
  Array of subscriptions to create. Minimum 1, maximum 25 items per request (10 in development environments).

  <Expandable title="properties">
    <ParamField body="subscriptions[].entityId" type="string" required>
      The unique identifier of the contact or company to subscribe to. Maximum length 255 characters.
    </ParamField>

    <ParamField body="subscriptions[].entityType" type="string">
      Overrides `defaults.entityType` for this item. Accepted values: `contact`, `company`.
    </ParamField>

    <ParamField body="subscriptions[].signalTypes" type="string[]">
      Overrides `defaults.signalTypes` for this item.
    </ParamField>

    <ParamField body="subscriptions[].name" type="string">
      Overrides the default `name` for this item. Maximum 100 characters.
    </ParamField>
  </Expandable>
</ParamField>

## Example request

```bash cURL theme={null}
curl --request POST \
  --url https://api.lusha.com/api/subscriptions \
  --header 'api_key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "defaults": {
      "url": "https://example.com/webhooks/lusha",
      "entityType": "contact",
      "signalTypes": ["promotion", "companyChange"]
    },
    "subscriptions": [
      { "entityId": "123456", "name": "My Test Webhook" }
    ]
  }'
```

## Example response

<ResponseExample>
  ```json 201 theme={null}
  {
    "total": 1,
    "successful": 1,
    "failed": 0,
    "results": [
      {
        "index": 0,
        "success": true,
        "subscription": {
          "id": "507f1f77bcf86cd799439011",
          "entityType": "contact",
          "entityId": "123456",
          "signalTypes": ["promotion", "companyChange"],
          "url": "https://example.com/webhooks/lusha",
          "name": "My Test Webhook",
          "isActive": true,
          "createdAt": "2026-02-02T10:00:00.000Z",
          "updatedAt": "2026-02-02T10:00:00.000Z"
        }
      }
    ]
  }
  ```

  ```json 400 theme={null}
  {
    "statusCode": 400,
    "message": "Validation failed",
    "errors": ["entityType must be one of: contact, company"]
  }
  ```
</ResponseExample>

<ResponseField name="total" type="integer">
  Total number of subscription creation attempts.
</ResponseField>

<ResponseField name="successful" type="integer">
  Number of subscriptions created successfully.
</ResponseField>

<ResponseField name="failed" type="integer">
  Number of subscription creation attempts that failed.
</ResponseField>

<ResponseField name="results" type="object[]">
  One entry per item in the request `subscriptions` array, in the same order. Each entry has `index` and `success`, plus either a `subscription` object (on success) or an `error` object with `code` and `message` (on failure) - for example a `DUPLICATE_SUBSCRIPTION` error if the entity is already subscribed.
</ResponseField>

<Note>
  This endpoint supports partial success: some subscriptions in the request can be created while others fail (for example, due to a duplicate entity). Check `failed` and inspect `results` to see which items succeeded.
</Note>

## Webhook payload structure

When a signal fires, Lusha sends a POST request to the subscription's webhook URL. The payload structure depends on the signal type.

<CodeGroup>
  ```json Promotion signal (contact) theme={null}
  {
    "id": "f3b87e05-0402-4f3e-8e26-6a38fd0ad62c",
    "type": "promotion",
    "entityType": "contact",
    "entityId": "4158887495",
    "subscriptionId": "507f1f77bcf86cd799439011",
    "data": {
      "personId": 4158887495,
      "currentCompanyId": 40823133,
      "currentCompanyName": "OMG Hospitality Group LLC",
      "currentDomain": "omghospitalitygroup.com",
      "currentTitle": "Bartender",
      "currentDepartments": [
        { "id": 7, "value": "Other" }
      ],
      "previousCompanyName": "First Watch Restaurants",
      "previousDomain": "firstwatch.com",
      "signalDate": "2025-07-01"
    },
    "timestamp": "2026-01-14T16:16:35.841Z",
    "billing": {
      "creditsCharged": 1
    }
  }
  ```

  ```json Commercial activity news signal (company) theme={null}
  {
    "id": "a7c92f14-1234-4b3e-9d22-8b4fe1d0bc45",
    "type": "commercialActivityNews",
    "entityType": "company",
    "entityId": "33222678",
    "subscriptionId": "507f1f77bcf86cd799439011",
    "data": {
      "companyId": "33222678",
      "companyName": "Lusha",
      "domain": "lusha.com",
      "signalId": "1503910",
      "eventType": "partnership",
      "eventSummary": "Lusha announced a strategic partnership with Salesforce.",
      "articlePublishedDate": "2025-06-15",
      "articleTitle": "Lusha Partners with Salesforce",
      "articleHighlight": "The partnership enables Salesforce users to access Lusha data directly within their CRM.",
      "eventEffectiveDate": "2025-06-10",
      "articleUrl": "https://example.com/lusha-salesforce-partnership"
    },
    "timestamp": "2026-01-14T16:16:35.841Z",
    "billing": {
      "creditsCharged": 1
    }
  }
  ```
</CodeGroup>

## Delivery headers

Lusha includes the following headers in every webhook delivery:

| Header              | Description                                                     |
| ------------------- | --------------------------------------------------------------- |
| `X-Lusha-Signature` | HMAC-SHA256 signature for verifying the request came from Lusha |
| `X-Lusha-Timestamp` | Unix timestamp of when the request was sent                     |
| `Content-Type`      | `application/json`                                              |
| `User-Agent`        | `Lusha-Webhooks/1.0`                                            |

## Required acknowledgment response

Your endpoint must respond within **10 seconds** with an HTTP `2xx` status and the following JSON body:

```json theme={null}
{
  "received": true,
  "timestamp": "2026-02-05T10:30:45.123Z",
  "webhookId": "f3b87e05-0402-4f3e-8e26-6a38fd0ad62c"
}
```

<ResponseField name="received" type="boolean" required>
  Must be `true` to confirm receipt.
</ResponseField>

<ResponseField name="timestamp" type="string" required>
  ISO 8601 timestamp of when your server received the request.
</ResponseField>

<ResponseField name="webhookId" type="string" required>
  The `id` value copied from the incoming webhook payload.
</ResponseField>

Return the acknowledgment before performing any heavy processing. Queue the payload for async handling if needed:

```javascript theme={null}
app.post('/webhook', async (req, res) => {
  // 1. Verify signature first
  if (!verifyWebhookSignature(req)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // 2. Queue for async processing
  await queueWebhook(req.body);

  // 3. Acknowledge immediately
  res.status(201).json({
    received: true,
    timestamp: new Date().toISOString(),
    webhookId: req.body.id
  });
});
```

## Delivery and retry behavior

* Lusha retries failed deliveries up to **3 times** with exponential backoff.
* A non-`2xx` response or a timeout triggers the retry mechanism.
* After all 3 retries are exhausted, the subscription is **automatically disabled**.
* All delivery attempts are recorded in [audit logs](/api-reference/webhooks/get-audit-logs).

<Warning>
  Retries do not incur additional credit charges. Each signal is charged once, at the time it is first delivered.
</Warning>

## Error responses

```json theme={null}
{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": ["entityType must be one of: contact, company"]
}
```

| Field        | Type      | Description                           |
| ------------ | --------- | ------------------------------------- |
| `statusCode` | number    | HTTP status code                      |
| `message`    | string    | Human-readable error message          |
| `errors`     | string\[] | Detailed validation errors (optional) |


## OpenAPI

````yaml post /api/subscriptions
openapi: 3.0.3
info:
  title: Lusha API Documentation
  version: 0.0.1
  x-logo:
    url: https://www.lusha.com/logo.png
  license:
    name: Proprietary
    url: https://lusha.com/legal/terms
  description: >
    <blockquote class="callout">

     **This is the Lusha API V3 documentation.** 
     
     V3 introduces a new search-then-enrich pattern, bulk operations, AI-powered lookalikes, and richer filter capabilities. All endpoints are under `https://api.lusha.com/v3/`.

      For more information on V3, refer to the [Migration Guide](/tutorials/v3-migration-guide).

    </blockquote>

      --- 

    Lusha provides a RESTful API for querying a comprehensive dataset of
    business profiles and company information. Built for teams running
    prospecting, enrichment, automation, and analytics workflows that need
    accurate, continuously updated business data. The API supports both
    real-time and bulk use cases.


    Use the Lusha API to **search for new prospects**, **enrich existing
    records**, **react to real-world changes**, and **expand coverage** with
    AI-powered lookalike recommendations.


    > All API requests must be made over **HTTPS**. All responses are returned
    in **JSON** format.


    --- 

    ## Available Endpoints


    | Category | Description |

    |---|---|

    | [**Search**](#tag/Search) | Find contacts or companies using known
    identifiers |

    | [**Enrich**](#tag/Enrich) | Retrieve full profile data for contacts or
    companies by ID |

    | [**Search & Enrich**](#tag/Search-and-Enrich) | Find and retrieve full
    contact or company data in a single call |

    | [**Prospecting**](#tag/Prospecting) | Filter-based search across contacts
    and companies |

    | [**Lookalikes**](#tag/Lookalikes) | AI-powered recommendations for similar
    contacts and companies |

    | [**Buying Group**](#tag/Buying-Group) | Identify decision makers,
    champions, and end users within target accounts |

    | [**Contacts Tables**](#tag/Contacts-Tables) | Persist, organize, and
    enrich contacts in reusable tables |

    | [**Companies Tables**](#tag/Companies-Tables) | Persist, organize, and
    enrich companies in reusable tables |

    | [**Signals**](#tag/Signals) | Real-world activity data for contacts and
    companies |

    | [**Website Visitors**](#tag/Website-Visits) | Companies ranked by
    website-visit signals for your tracked domains |

    | [**Conversations**](#tag/Conversations) | Search recorded sales
    conversations and fetch their transcripts |

    | [**Filters**](#tag/Filters) | Discover valid filter values for prospecting
    |

    | [**Webhooks**](#tag/Webhooks) | Real-time signal notifications via HTTP
    callbacks |

    | [**Account**](#tag/Account) | Usage, credits, rate limits, and pricing |


    <blockquote class="callout">

     **Waterfall Reveal for Contact Enrichment.**

      Enrich Contacts now supports `waterfallEnabled`. Fall through to your enabled third-party providers when Lusha's own data has no match, for extra reach on hard-to-match contacts. On by default once your account has it turned on - pass `waterfallEnabled: false` to opt a specific call out. [See Enrich Contacts](#operation/enrichContacts).

    </blockquote>


    ---


    ## Data Source and Privacy


    **Lusha is a search platform.** The data provided is not created or directly
    managed by Lusha. It is sourced from publicly available information and
    trusted business partners.


    For more details on how we collect and handle data, see our [Privacy
    Policy](https://lusha.com/legal/privacy-notice/).


    ---


    ## Legal Notices


    (a) Data brokers and other third-party platforms may not embed, expose, or
    otherwise provide access to the Lusha API, or to Data obtained through it,
    on or through their own website, product, or service, without Lusha's prior
    written consent.


    (b) Data obtained through the API may not be used to train or develop AI/ML
    systems, subject to the terms and exceptions outlined in the [Terms and
    Conditions](https://lusha.com/legal/terms).


    ---


    ## Authentication


    All API requests require an **API key** linked to your Lusha account and
    plan. Pass your key in the `api_key` request header on every call.


    > Generate and manage your API key in the [Lusha
    dashboard](https://dashboard.lusha.com/enrich/api).


    Store your API key securely and use it only in **server-side environments**.


    ---


    ## Rate Limiting


    Lusha enforces rate limits on a per-plan basis to ensure fair usage and
    platform stability. Limits are applied across multiple time windows (per
    minute, per hour, and per day), and vary depending on your account plan.


    Rate limits for the **Credit Usage API** differ from standard endpoint
    limits.


    > **Note:** To check your current plan's limits, visit the [Lusha Help
    Center](https://info.lusha.com/en/articles/163856-all-there-is-to-know-about-lusha-s-api)
    or contact your account manager.


    **Rate Limit Response Headers**


    | Header | Description |

    |--------|-------------|

    | `x-rate-limit-daily` | Total requests allowed per day |

    | `x-daily-requests-left` | Requests remaining in your daily quota |

    | `x-daily-usage` | Requests made in the current daily period |

    | `x-rate-limit-hourly` | Total requests allowed per hour |

    | `x-hourly-requests-left` | Requests remaining in your hourly quota |

    | `x-hourly-usage` | Requests made in the current hourly period |

    | `x-rate-limit-minute` | Total requests allowed per minute |

    | `x-minute-requests-left` | Requests remaining in the current minute window
    |

    | `x-minute-usage` | Requests made in the current minute window |


    ---

    ## Error Codes


    Lusha uses standard HTTP status codes to indicate the result of each
    request.


    | Code | Name | Description |

    |------|------|-------------|

    | `200` | OK | Request was successful |

    | `400` | Bad Request | Request is malformed or missing required fields |

    | `401` | Unauthorized | API key is missing or invalid |

    | `402` | Payment Required | Insufficient credits or payment needed |

    | `403` | Forbidden | Account is inactive. Contact support@lusha.com |

    | `404` | Not Found | Endpoint or resource does not exist |

    | `429` | Too Many Requests | Rate limit or daily quota exceeded |

    | `451` | Unavailable For Legal Reasons | Request blocked due to GDPR
    regulations |

    | `499` | Client Closed Request | Request timed out before completing |

    | `5XX` | Server Error | Issue on Lusha's end. Retry with exponential
    backoff |


    **Error Response Format**


    ```json

    {
      "statusCode": 400,
      "message": "Invalid request parameters"
    }

    ```


    **Tables-specific error codes**


    | Code | Status | Meaning |

    |---|---|---|

    | `TABLE_NOT_FOUND` | 404 | The `table_id` does not exist or is not
    accessible to this account |

    | `COLUMN_NOT_FOUND` | 404 | The `column_id` does not exist on the given
    table |

    | `TABLE_NAME_CONFLICT` | 409 | A table with this name already exists |


    Tables error bodies use the shape `{ "message": "...", "code": <status>, ...
    }` rather than the `statusCode`/`errors` shape used elsewhere in this doc.


    **Limits:** up to 500 entity IDs per add/remove call · max 50,000 entities
    per table · max 500 tables per account · `page` 0–100 · `size` default 100.


    **Tips for Handling Errors**


    - Verify your API key is correct and active

    - Read the `message` field for specific troubleshooting details

    - For `429` errors, wait before retrying

    - For `5XX` errors, use exponential backoff before retrying
  contact:
    name: Lusha Support
    url: https://api.lusha.com
    email: support@lusha.com
  termsOfService: https://lusha.com/legal/terms
  x-privacy-policy:
    name: Privacy Policy
    url: https://lusha.com/legal/privacy-notice/
servers:
  - url: https://api.lusha.com
    description: Production server
security:
  - ApiKeyAuth: []
tags:
  - name: Search
    description: >
      **Search APIs:** Find contacts or companies using known identifiers.


      Look up contacts by `id`, `linkedinUrl`, `email`, or `firstName` +
      `lastName` + `companyName`/`companyDomain`. Look up companies by `id`,
      `name`, or `domain`.


      Returns a non-PII preview of each profile with a `has` field listing
      available data points and a `canReveal` field showing what can be unlocked
      via Enrich.


      > **Billing:** Charged per successful result via the `api_search` action.
    x-tag-expanded: true
  - name: Enrich
    description: >
      **Enrich APIs:** Retrieve full profile data for contacts or companies by
      ID.


      Pass IDs from Search results to reveal emails, phones, and full
      firmographic data.


      > **Billing:** Charged per revealed field via per-datapoint pricing
      (`revealEmail`, `revealPhone`, `reveal_company`).
    x-tag-expanded: true
  - name: Search & Enrich
    description: >
      **Search & Enrich APIs:** Find and retrieve full contact or company data
      in a single call.


      Combines Search and Enrich into one request. Provide identifiers and
      control what gets revealed via the `reveal` field. Premium data points are
      never returned unless you request them explicitly in `reveal`.


      > **Billing:** Two charges apply - one for the search (`api_search`) and
      one per revealed field.
    x-tag-expanded: true
  - name: Prospecting
    description: >
      **Prospecting APIs:** Filter-based search for contacts and companies.


      Use prospecting to find new records that match your Ideal Customer Profile
      (ICP). Apply rich filters across:


      - **Contact attributes:** title, seniority, location, signals

      - **Company attributes:** size, revenue, industry, technologies, intent


      Pass `tableId` to also persist matching results into an existing table.
      See [Contacts Tables](#tag/Contacts-Tables) or [Companies
      Tables](#tag/Companies-Tables).


      > **Billing:** Uses the capture/charge model with `api_search` actions.
      Signal charges apply additionally.
    x-tag-expanded: true
  - name: Lookalikes
    description: >
      **Lookalike APIs:** Use AI-powered recommendations to discover contacts
      and companies similar to your best existing customers. The Contact
      Lookalikes and Company Lookalikes endpoints return paginated results you
      can pipe directly into Enrich for full data.


      Pass `tableId` to also persist matching results into an existing table.
      See [Contacts Tables](#tag/Contacts-Tables) or [Companies
      Tables](#tag/Companies-Tables).
    x-tag-expanded: true
  - name: Buying Group
    description: >
      **Buying Group API:** Identify and prioritize the buying committee within
      a set of target companies.


      Supply up to 25 companies by `domain` or Lusha company `id`. The model
      scores and labels each returned contact with a persona role -
      `decision_maker`, `potential_champion`, or `end_user` - so you can
      prioritize outreach across the buying committee instead of working one
      contact at a time.


      Results are lightweight previews grouped by company. Use [Enrich
      Contacts](#operation/enrichContacts) with the returned `id` to reveal
      emails and phones.


      > **Billing:** Charged per contact returned via the `buyingGroupContact`
      action.
    x-tag-expanded: true
  - name: Contacts Tables
    description: >
      **Contacts Tables API:** Create and manage persistent tables of contacts
      inside Lusha.


      Tables are spreadsheets with configurable columns - default Lusha fields,
      enrichment data, Signals, AI insights, premium data points, CRM fields,
      and custom fields. Populate a table directly through the endpoints below,
      or pass `tableId` on Prospecting, Enrich, Signals, or Lookalike calls to
      persist those results automatically.


      Every surface that touches table data - this API, MCP, and the Workspace
      UI - reads and writes the same underlying data. Changes made through one
      surface are reflected on the others.


      **Working with tables:**

      - **Tables** - create, list, get status, update
      (rename/archive/visibility), delete

      - **Entities** - add, remove, or read the rows in a table

      - **Columns** - browse the Lusha column catalog, add columns, list,
      remove, or run a column across a table's rows


      **Owner resolution:** `owner.email` resolves to a user on your account and
      determines table ownership. **Required on every call when authenticating
      with an API key** - omitting it returns `400`. Optional for OAuth/token
      callers, since the caller is already identified by the token. Sent in the
      body as `owner: { email }` on `POST`/`PATCH` calls (and on `DELETE
      .../entities`, which carries a body); sent as a `?email=` query parameter
      on other `GET`/`DELETE` calls, which have no body.


      **Billing:**

      - Adding contacts to a table is free.

      - Reading entities (`GET .../entities`) charges per row returned.

      - Create / List / Get / Update / Delete / Column Catalog / Add Columns /
      List Columns / Remove Column / Remove Entities are free. (Add Columns is
      free today - credits aren't charged for it yet.)

      - Running a column charges per row per the column's tier (contact
      enrichment per row with data; signal/AI/score per row per run).

      - Non-public-API-plan accounts always resolve to `0` credits charged.


      **Limits:** up to 500 entity IDs per add/remove call · max 50,000 entities
      per table · max 500 tables per account.


      See also: [Companies Tables](#tag/Companies-Tables).
    x-tag-expanded: true
  - name: Companies Tables
    description: >
      **Companies Tables API:** Create and manage persistent tables of companies
      inside Lusha.


      Tables are spreadsheets with configurable columns - default Lusha fields,
      enrichment data, Signals, AI insights, premium data points, CRM fields,
      and custom fields. Populate a table directly through the endpoints below,
      or pass `tableId` on Prospecting, Enrich, Signals, or Lookalike calls to
      persist those results automatically.


      Every surface that touches table data - this API, MCP, and the Workspace
      UI - reads and writes the same underlying data. Changes made through one
      surface are reflected on the others.


      **Working with tables:**

      - **Tables** - create, list, get status, update
      (rename/archive/visibility), delete

      - **Entities** - add, remove, or read the rows in a table

      - **Columns** - browse the Lusha column catalog, add columns, list,
      remove, or run a column across a table's rows


      **Owner resolution:** `owner.email` resolves to a user on your account and
      determines table ownership. **Required on every call when authenticating
      with an API key** - omitting it returns `400`. Optional for OAuth/token
      callers, since the caller is already identified by the token. Sent in the
      body as `owner: { email }` on `POST`/`PATCH` calls (and on `DELETE
      .../entities`, which carries a body); sent as a `?email=` query parameter
      on other `GET`/`DELETE` calls, which have no body.


      **Billing:**

      - Adding companies to a table charges `reveal_company` per **newly added**
      company, deduped so duplicates and already-present companies aren't
      charged again.

      - Reading entities (`GET .../entities`) charges per row returned.

      - Create / List / Get / Update / Delete / Column Catalog / Add Columns /
      List Columns / Remove Column / Remove Entities are free. (Add Columns is
      free today - credits aren't charged for it yet.)

      - Running a column charges per row per the column's tier (company
      enrichment once per company per table - re-runs on an already-paid company
      are free; signal/AI/score per row per run).

      - Non-public-API-plan accounts always resolve to `0` credits charged.


      **Limits:** up to 500 entity IDs per add/remove call · max 50,000 entities
      per table · max 500 tables per account.


      See also: [Contacts Tables](#tag/Contacts-Tables).
    x-tag-expanded: true
  - name: Signals
    description: >
      Real-world activity data for contacts and companies.


      Signals are available as standalone endpoints or as an optional `signals`
      filter on Search and Prospecting endpoints.



      **Contact signal types:** `promotion`, `companyChange`, `allSignals`


      ----


      **Company signal types:** `headcountIncrease1m/3m/6m/12m`,
      `headcountDecrease1m/3m/6m/12m`, `surgeInHiring`,
      `surgeInHiringByDepartment`, `surgeInHiringByLocation`,
      `websiteTrafficIncrease`, `websiteTrafficDecrease`, `itSpendIncrease`,
      `itSpendDecrease`, `riskNews`, `commercialActivityNews`,
      `corporateStrategyNews`, `financialEventsNews`, `peopleNews`,
      `marketIntelligenceNews`, `productActivityNews`, `allSignals`


      ----


      **Signal Score:** Use [Score Companies by Signal
      Activity](#operation/getCompanySignalScores) or [Score Contacts by Signal
      Activity](#operation/getContactSignalScores) to get a single aggregate
      momentum score ([0,1]) plus the active signal breakdown for a batch of
      entities, rather than a raw event list.


      ----


      Credits are charged per matched signal per result via `showSignalsContact`
      or `showSignalsCompany`.


      Pass `tableId` to also persist matching results into an existing table.
      See [Contacts Tables](#tag/Contacts-Tables) or [Companies
      Tables](#tag/Companies-Tables).
    x-tag-expanded: true
  - name: Website Visits
    description: >
      Retrieve companies ranked by website-visit signals for your tracked
      domains.

       Domains must be configured for tracking in the dashboard. Each result combines a V3 company firmographic preview with behavioral visit metrics (score, sessions, unique visitors, avg session length, and more).
    x-tag-expanded: true
  - name: Conversations
    description: >
      **Conversations API:** Search the sales conversations recorded by Lusha
      Conversations for your account, and fetch speaker-attributed transcripts.


      Search Conversations returns each conversation's metadata, AI summary,
      action items, risks, objections, competitor mentions, coaching analysis,
      and chapters - transcripts are not included. Fetch the transcript for a
      single conversation separately.


      **Two search modes on one contract:**

      - **Keyword mode** - supply `query` to rank conversations by transcript
      content. All other filters are ignored.

      - **Filter mode** - omit `query` and supply the structural filters (dates,
      contact names, company domains, meeting titles).


      Only conversations belonging to your account whose post-call processing
      has completed are returned. `summary`, `coaching`, and `chapters` come
      from an asynchronous pipeline and are `null`/empty until it has run - a
      `null` summary means "analysis not ready yet", not "nothing found".


      > **Billing:** Search charges 1 credit per block of up to 25 conversations
      returned (via `ci_meeting_data_export`); a request that returns nothing is
      free. Transcript charges 1 credit per successful request (via
      `ci_transcript_analysis`); a `404` is never charged. While the relevant
      action isn't yet seeded on your account's pricebook, the endpoint stays
      free (`billing.creditsCharged` is `0`).
    x-tag-expanded: true
  - name: Filters
    description: >
      **Filter APIs:** Retrieve available filter values for prospecting.


      Use the discovery endpoints to list all available filter types, then fetch
      valid values for a specific filter type before building a prospecting
      request.


      **Contact filter types:** `departments`, `seniority`,
      `existingDataPoints`, `countries`, `locations`


      **Company filter types:** `names`, `sizes`, `revenues`, `locations`,
      `sics`, `naics`, `industriesLabels`, `intentTopics`, `technologies`
    x-tag-expanded: true
  - name: Webhooks
    description: >
      Subscribe to real-time notifications when contacts change jobs or
      companies experience key business events.


      Webhooks deliver HTTP POST requests to your endpoints when signals occur -
      from promotions and job changes to company growth.


      > For a full list of available signals, refer to [**Signal
      Options**](https://docs.lusha.com/apis/openapi/signals/getsignaloptions).

      ---

      **Key Features:**

      - Real-time contact & company signal notifications

      - Bulk subscription management (up to 25 items per request)

      - Secure delivery with HMAC-SHA256 signatures

      - Delivery monitoring with audit logs

       **Available Endpoints:**

      | Method | Endpoint | Purpose |

      |--------|----------|---------|

      | POST | `/api/subscriptions` | Create subscriptions (bulk supported) |

      | GET | `/api/subscriptions` | List all subscriptions |

      | GET | `/api/subscriptions/{id}` | Get subscription by ID |

      | PATCH | `/api/subscriptions/{id}` | Update subscription |

      | POST | `/api/subscriptions/delete` | Delete subscriptions (bulk
      supported) |

      | POST | `/api/subscriptions/{id}/test` | Test subscription delivery |

      | GET | `/api/audit-logs` | Get webhook delivery logs |

      | GET | `/api/audit-logs/stats` | Get delivery statistics |

      | GET | `/api/account/secret` | Get account webhook secret |

      | POST | `/api/account/secret/regenerate` | Regenerate account secret |

      | POST | `/api/subscriptions/opt-out` | Subscribe to contact opt-out
      notifications |


      > **Webhook Delivery Acknowledgment:** When receiving webhook deliveries
      (POST requests), your endpoint must acknowledge with a specific response
      format. See the [Create Subscription](#operation/createSubscription)
      endpoint for the required acknowledgment structure.
            ---

      <details>

      <summary><strong>Rate Limits</strong></summary>


      | Operation | Limit |

      |-----------|-------|

      | API Requests | 100 requests/minute per account |

      | Create Subscriptions | 25 items per request |

      | Delete Subscriptions | 25 items per request |


      </details>


      ---


      <details>

      <summary><strong>Security & Verification</strong></summary>


      **HTTPS Requirement:**

      - Production webhook URLs **must** use HTTPS

      - HTTP URLs are not accepted


      **Signature Verification:**


      All webhook deliveries include an `X-Lusha-Signature` header containing an
      HMAC-SHA256 signature. Verify this signature to ensure the request is from
      Lusha:


      1. Extract the `X-Lusha-Signature` and `X-Lusha-Timestamp` headers

      2. Concatenate: `timestamp + "." + JSON.stringify(payload)`

      3. Compute HMAC-SHA256 using your webhook secret

      4. Compare the computed signature with the received signature


      **Example (Node.js):**

      ```javascript

      const crypto = require('crypto');


      function verifySignature(payload, signature, timestamp, secret) {
        const signedPayload = `${timestamp}.${JSON.stringify(payload)}`;
        const expectedSignature = crypto
          .createHmac('sha256', secret)
          .update(signedPayload)
          .digest('hex');
        
        return crypto.timingSafeEqual(
          Buffer.from(signature),
          Buffer.from(expectedSignature)
        );
      }

      ```


      > **Security Best Practice:** Always verify webhook signatures to prevent
      spoofed requests.


      </details>


      ---


      <details>

      <summary><strong>Credits & Billing</strong></summary>


      **Credit Charges:**

      - Credits are charged when signals are detected and delivered to your
      webhook

      - The `creditsCharged` field in the webhook payload indicates how many
      credits were used

      - Credits are deducted from your account balance per signal type


      **No Duplicate Charges:**

      - Each signal is delivered once and charged once

      - Webhook delivery retries do not incur additional charges


      </details>


      ---


      <details>

      <summary><strong>Error Response Format</strong></summary>


      All error responses follow this format:

      ```json

      {
        "statusCode": 400,
        "message": "Validation failed",
        "errors": ["entityType must be one of: contact, company"]
      }

      ```


      | Field | Type | Description |

      |-------|------|-------------|

      | `statusCode` | number | HTTP status code |

      | `message` | string | Error message |

      | `errors` | string[] | Detailed error messages (optional) |


      </details>
          
      ---
    x-tag-expanded: true
  - name: Account
    description: >
      **Account API:** Retrieve account usage, credit balance, rate limits, plan
      details, and pricing.


      Use this endpoint to monitor consumption and understand the credit cost of
      each action type in the public API flow.


      > **Rate limit:** 5 requests per minute.
    x-tag-expanded: true
paths:
  /api/subscriptions:
    post:
      tags:
        - Webhooks
      summary: Create Subscription
      description: >
        Creates one or more webhook subscriptions for real-time signal
        notifications.


        **Delivery & Reliability:**

        - Webhooks are delivered with automatic retry on failures

        - Maximum 3 retry attempts with exponential backoff

        - Subscriptions auto-disable after max retries exceeded

        - All deliveries are logged in audit logs


        > **Note:** Your webhook endpoint must respond with a proper
        acknowledgment. 
         See Client Response Format below for details.

        > **Limit:** Maximum 25 subscriptions per request


        *Endpoint*: **(POST) https://api.lusha.com/api/subscriptions**


        ---


        ### Webhook Payload You'll Receive
         When a signal is triggered, this payload is sent to your webhook URL:
        ```json
            {
              "id": "f3b87e05-0402-4f3e-8e26-6a38fd0ad62c",
              "type": "promotion",
              "entityType": "contact",
              "entityId": "4158887495",
              "subscriptionId": "507f1f77bcf86cd799439011",
              "data": {
                "personId": 4158887495,
                "currentCompanyId": 40823133,
                "currentCompanyName": "OMG Hospitality Group LLC",
                "currentDomain": "omghospitalitygroup.com",
                "currentTitle": "Bartender",
                "currentDepartments": [
                  { "id": 7, "value": "Other" }
                ],
                "previousCompanyName": "First Watch Restaurants",
                "previousDomain": "firstwatch.com",
                "signalDate": "2025-07-01"
              },
              "timestamp": "2026-01-14T16:16:35.841Z",
              "billing": {
                "creditsCharged": 1
              }
            }
            ```
                    **Example - Company News Signal:**
            ```json
                    {
                      "id": "a7c92f14-1234-4b3e-9d22-8b4fe1d0bc45",
                      "type": "commercialActivityNews",
                      "entityType": "company",
                      "entityId": "33222678",
                      "subscriptionId": "507f1f77bcf86cd799439011",
                      "data": {
                        "companyId": "33222678",
                        "companyName": "Lusha",
                        "domain": "lusha.com",
                        "signalId": "1503910",
                        "eventType": "partnership",
                        "eventSummary": "Lusha announced a strategic partnership with Salesforce.",
                        "articlePublishedDate": "2025-06-15",
                        "articleTitle": "Lusha Partners with Salesforce",
                        "articleHighlight": "The partnership enables Salesforce users to access Lusha data directly within their CRM.",
                        "eventEffectiveDate": "2025-06-10",
                        "articleUrl": "https://example.com/lusha-salesforce-partnership"
                      },
                      "timestamp": "2026-01-14T16:16:35.841Z",
                      "billing": {
                        "creditsCharged": 1
                      }
                    }
                  ```

              **Headers Included:**

              | Header | Description |
              |--------|-------------|
              | `X-Lusha-Signature` | HMAC-SHA256 signature for verification |
              | `X-Lusha-Timestamp` | Unix timestamp of the request |
              | `Content-Type` | application/json |
              | `User-Agent` | Lusha-Webhooks/1.0 |


        ---

        ⚠️ **Important:** Ensure your account has a webhook secret before
        creating subscriptions.

        Create one via the [Regenerate Account
        Secret](#operation/regenerateAccountSecret) endpoint.


        ---


        ### Client Response Format (Required)


        When your webhook endpoint receives a delivery, it **must** acknowledge
        receipt with this response:

          **Required Response:**
          ````json
          {
            "received": true,
            "timestamp": "2026-02-05T10:30:45.123Z",
            "webhookId": "f3b87e05-0402-4f3e-8e26-6a38fd0ad62c"
          }
          ````

        <details>

        <summary><strong>Response Requirements</strong></summary>

          | Requirement | Value |
          |-------------|-------|
          | **HTTP Status** | `201 Created` (recommended) or any `2xx` status |
          | **Content-Type** | `application/json` |
          | **Response Time** | Within 10 seconds |
        </details>



        <details>

        <summary><strong>Field Descriptions & Implementation
        Guide</strong></summary>

          **Field Descriptions:**
          * `received` (boolean, required): Confirmation flag - must be `true`
          * `timestamp` (string, required): ISO 8601 timestamp of receipt
          * `webhookId` (string, required): Echo the `id` from webhook payload

          **Implementation Example:**
          ```javascript
          app.post('/webhook', async (req, res) => {
            // 1. Verify signature
            if (!verifyWebhookSignature(req)) {
              return res.status(401).json({ error: 'Invalid signature' });
            }
            
            // 2. Queue for async processing
            await queueWebhook(req.body);
            
            // 3. Acknowledge immediately
            res.status(201).json({
              received: true,
              timestamp: new Date().toISOString(),
              webhookId: req.body.id
            });
            ```

          **Important Notes:**
          * Return acknowledgment **before** heavy processing
          * Non-2xx responses trigger retry mechanism
          * After 3 failed retries, subscription is disabled

          </details>

        ----
      operationId: createSubscription
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSubscriptionRequest'
            examples:
              singleSubscription:
                summary: Create a single subscription
                value:
                  defaults:
                    entityType: contact
                    signalTypes:
                      - promotion
                      - companyChange
                    url: https://example.com/webhooks/lusha
                  subscriptions:
                    - entityId: '123456'
                      name: My Test Webhook
              multipleSubscriptions:
                summary: Create multiple subscriptions with shared URL
                value:
                  defaults:
                    entityType: contact
                    signalTypes:
                      - promotion
                      - companyChange
                    url: https://example.com/webhooks/lusha
                  subscriptions:
                    - entityId: '123'
                      name: Contact 123
                    - entityId: '456'
                      name: Contact 456
                    - entityId: '789'
                      name: Contact 789
              mixedEntityTypes:
                summary: Mixed entity types with shared URL
                value:
                  defaults:
                    signalTypes:
                      - promotion
                      - itSpendIncrease
                    url: https://example.com/webhooks/lusha
                  subscriptions:
                    - entityType: contact
                      entityId: '123'
                    - entityType: company
                      entityId: '456'
      responses:
        '201':
          description: Subscriptions created (full or partial success)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSubscriptionResponse'
              examples:
                allSuccessful:
                  summary: All subscriptions created successfully
                  value:
                    total: 3
                    successful: 3
                    failed: 0
                    results:
                      - index: 0
                        success: true
                        subscription:
                          id: 507f1f77bcf86cd799439011
                          entityType: contact
                          entityId: '123'
                          signalTypes:
                            - promotion
                            - companyChange
                          url: https://example.com/webhooks/lusha
                          name: Contact 123
                          isActive: true
                          createdAt: '2026-02-02T10:00:00.000Z'
                          updatedAt: '2026-02-02T10:00:00.000Z'
                partialSuccess:
                  summary: Some subscriptions failed (partial success)
                  value:
                    total: 3
                    successful: 2
                    failed: 1
                    results:
                      - index: 0
                        success: true
                        subscription:
                          id: 507f1f77bcf86cd799439011
                          entityType: contact
                          entityId: '123'
                          signalTypes:
                            - promotion
                            - companyChange
                          url: https://example.com/webhooks/lusha
                          name: Contact 123
                          isActive: true
                          createdAt: '2026-02-02T10:00:00.000Z'
                          updatedAt: '2026-02-02T10:00:00.000Z'
                      - index: 1
                        success: false
                        error:
                          code: DUPLICATE_SUBSCRIPTION
                          message: >-
                            Subscription already exists for entity type
                            'contact' with entity ID '456'
        '400':
          description: Bad request - URL validation failed or invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                statusCode: 400
                message: Validation failed
                errors:
                  - 'entityType must be one of: contact, company'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Forbidden - feature not available or limit reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                statusCode: 403
                message: Maximum subscriptions limit reached for your account
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    CreateSubscriptionRequest:
      type: object
      required:
        - defaults
        - subscriptions
      properties:
        defaults:
          type: object
          required:
            - url
          properties:
            url:
              type: string
              format: uri
              maxLength: 2048
              description: Webhook URL (HTTPS required in production)
              example: https://example.com/webhooks/lusha
            entityType:
              type: string
              enum:
                - contact
                - company
              description: Default entity type for all subscriptions
              example: contact
            signalTypes:
              type: array
              items:
                type: string
              description: Default signal types for all subscriptions
              example:
                - promotion
        name:
          type: string
          maxLength: 100
          description: Default subscription name prefix
          example: Contact Webhook
        subscriptions:
          type: array
          minItems: 1
          maxItems: 25
          description: Array of subscriptions to create (max 25)
          items:
            type: object
            required:
              - entityId
            properties:
              entityId:
                type: string
                maxLength: 255
                description: Entity ID (always required per item)
                example: '123'
              entityType:
                type: string
                enum:
                  - contact
                  - company
                description: Overrides default entityType
              signalTypes:
                type: array
                items:
                  type: string
                description: Overrides default signalTypes
              name:
                type: string
                maxLength: 100
                description: Overrides default name
    CreateSubscriptionResponse:
      type: object
      required:
        - total
        - successful
        - failed
        - results
      properties:
        total:
          type: integer
          example: 3
        successful:
          type: integer
          example: 2
        failed:
          type: integer
          example: 1
        results:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/CreateSubscriptionSuccessResult'
              - $ref: '#/components/schemas/CreateSubscriptionErrorResult'
    ErrorResponse:
      type: object
      required:
        - statusCode
        - message
      properties:
        statusCode:
          type: integer
          description: HTTP status code
          example: 400
        message:
          type: string
          description: Error message
          example: Validation failed
        errors:
          type: array
          items:
            type: string
          description: Detailed error messages (optional, only for validation errors)
          example:
            - 'entityType must be one of: contact, company'
    CreateSubscriptionSuccessResult:
      type: object
      required:
        - index
        - success
        - subscription
      properties:
        index:
          type: integer
          example: 0
        success:
          type: boolean
          enum:
            - true
          example: true
        subscription:
          $ref: '#/components/schemas/SubscriptionWithoutSecret'
    CreateSubscriptionErrorResult:
      type: object
      required:
        - index
        - success
        - error
      properties:
        index:
          type: integer
          example: 1
        success:
          type: boolean
          enum:
            - false
          example: false
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - VALIDATION_ERROR
                - DUPLICATE_SUBSCRIPTION
                - URL_VALIDATION_FAILED
                - WEBHOOK_VERIFICATION_FAILED
                - FORBIDDEN
                - UNKNOWN_ERROR
              example: DUPLICATE_SUBSCRIPTION
            message:
              type: string
              example: >-
                Subscription already exists for entity type 'contact' with
                entity ID '456'
    SubscriptionWithoutSecret:
      type: object
      required:
        - id
        - entityType
        - entityId
        - signalTypes
        - url
        - isActive
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          example: 507f1f77bcf86cd799439011
        entityType:
          type: string
          enum:
            - contact
            - company
          example: contact
        entityId:
          type: string
          example: '123456'
        signalTypes:
          type: array
          items:
            type: string
          example:
            - promotion
            - companyChange
        url:
          type: string
          format: uri
          example: https://example.com/webhooks/lusha
        name:
          type: string
          example: Contact Promotion Tracker
        isActive:
          type: boolean
          example: true
        blockReason:
          type: string
          nullable: true
          description: Reason subscription was disabled (null if active)
          example: Max retries exceeded
        blockedAt:
          type: string
          format: date-time
          nullable: true
          description: When subscription was disabled (null if active)
          example: '2026-01-14T10:00:00.000Z'
        createdAt:
          type: string
          format: date-time
          example: '2026-01-14T10:00:00.000Z'
        updatedAt:
          type: string
          format: date-time
          example: '2026-01-14T10:00:00.000Z'
  responses:
    Unauthorized:
      description: Unauthorized - invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 401
            message: Invalid API key
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            statusCode: 500
            message: Internal server error. Please try again later.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: api_key
      description: >
        Your Lusha API key. You can find this in your Lusha dashboard under API
        settings.

        Include this key in the `api_key` header for all requests.

````