# Lusha API Documentation

<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 |
| [**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 |
| [**Decision Makers**](#tag/Decision-Makers) | Find the most relevant decision makers across your target accounts |
| [**Website Visitors**](#tag/Website-Visits) | Companies ranked by website-visit signals for your tracked domains |
| [**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">

 **`BETA` Waterfall Reveal for Contact Enrichment.**

 Enrich Contacts now supports `waterfallReveal`. Fall through to your enabled third-party providers when Lusha's own data has no match, for extra reach on hard-to-match contacts. This feature is currently in limited beta and isn't available to all accounts yet. **Contact [support@lusha.com](mailto:support@lusha.com)** to request access. [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/).

---

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


License: Proprietary

## Servers

Production server
```
https://api.lusha.com
```

## Security

### ApiKeyAuth

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.


Type: apiKey
In: header
Name: api_key

## Download OpenAPI description

[Lusha API Documentation](https://docs.lusha.com/_bundle/apis/@v3/openapi.yaml)

## Search

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


### Search Contacts

 - [POST /v3/contacts/search](https://docs.lusha.com/apis/openapi/search/searchcontacts.md): Look up contacts by identifier. Returns a non-PII preview of each profile — no emails or phone numbers.

Accepted identifiers (one required per contact):
- Lusha contact id
- linkedinUrl
- email
- firstName + lastName + companyName or companyDomain

Up to 100 contacts per request. Each result includes:
- has — data points available on this profile
- canReveal — what you can unlock via Enrich Contacts, and the credit cost

Pass a signals filter to narrow results to contacts with recent activity (e.g. promotion, job change).

> Billing: Charged per successful result via the api_search action.

### Search Companies

 - [POST /v3/companies/search](https://docs.lusha.com/apis/openapi/search/searchcompanies.md): Look up companies by identifier. Returns a preview of each company profile.

Accepted identifiers (at least one required per company):
- Lusha company id
- name
- domain

Up to 100 companies per request. Each result includes a has field listing the data available via Enrich Companies.

Pass a signals filter to narrow results to companies showing specific activity (e.g. headcount growth, hiring surge).

> Billing: Charged per successful result via the api_search action.

## Enrich

**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`).


### Enrich Contacts

 - [POST /v3/contacts/enrich](https://docs.lusha.com/apis/openapi/enrich/enrichcontacts.md): Reveal full contact data for contacts you've already found via Search Contacts.

Pass up to 100 contact ids (from the search response). Use the reveal field to control what gets unlocked:
- emails — work and personal email addresses
- phones — mobile and direct phone numbers
- Omit reveal to get both by default

---

###   BETA Waterfall Reveal
Fall through to your enabled third-party providers when Lusha's own data has no match, for extra reach on hard-to-match contacts.

Pass waterfallReveal with the fields (emails, phones) you want covered by the waterfall, alongside reveal:

json
        "reveal": ["emails", "phones"],
        "waterfallReveal": ["emails", "phones"]


- reveal controls which fields come back.
- waterfallReveal is the subset of those fields allowed to fall through to third-party providers.
- Requires Data Waterfall enabled on your account, with specific providers turned on, under Account > Waterfall. If waterfall is off or no providers are enabled, waterfallReveal has no additional effect beyond reveal.
- Use of Data Waterfall is subject to Lusha's Supplementary Terms.
- This feature is in limited beta and not yet available on all accounts. Contact support@lusha.com to request access.

---
> Tip: If canReveal.credits is 0 in the search response, that data has already been revealed for your account — re-enriching it is free.

> Billing: Charged per revealed field (email or phone) via per-datapoint pricing.

> Persisting to a table: Pass tableId to also add these contacts to an existing table and populate the Work email / Phone columns. See Contacts Tables.

### Enrich Companies

 - [POST /v3/companies/enrich](https://docs.lusha.com/apis/openapi/enrich/enrichcompanies.md): Reveal full company data for companies you've already found via Search Companies.

Pass up to 100 company ids (from the search response). Each enriched result includes:
- Firmographics: size, revenue range, year founded, company type
- Industry: primary industry, sub-industry, SIC/NAICS codes
- Locations: HQ and additional office sites
- Technologies, funding rounds, buyer intent topics
- LinkedIn followers, logo URL, social links

> Billing: Charged per successful result via the reveal_company action.

> Persisting to a table: Pass tableId to also add these companies to an existing table and populate the relevant enrichment columns. See Companies Tables.

## Search & Enrich

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

> **Billing:** Two charges apply — one for the search (`api_search`) and one per revealed field.


### Search and Enrich Contacts

 - [POST /v3/contacts/search-and-enrich](https://docs.lusha.com/apis/openapi/search-and-enrich/searchandenrichcontacts.md): Find contacts and reveal their full data in a single call. Combines Search and Enrich into one request.

Provide contact identifiers the same way you would for Search Contacts. Use the reveal field to control what gets unlocked (emails, phones, or both).

Up to 100 contacts per request.

> Billing: Two charges apply — one for the search (api_search) and one per revealed field. The billing.creditsCharged in the response reflects the total.

### Search and Enrich Companies

 - [POST /v3/companies/search-and-enrich](https://docs.lusha.com/apis/openapi/search-and-enrich/searchandenrichcompanies.md): Find companies and reveal their full data in a single call. Combines Search and Enrich into one request.

Provide company identifiers the same way you would for Search Companies. Up to 100 companies per request.

> Billing: Same as Enrich Companies — charged per successful result via the reveal_company action.

## Prospecting

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

Results are paginated: up to **1,000 pages x 50 results = 50,000 results** per query.

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.


### Prospecting Contacts

 - [POST /v3/contacts/prospecting](https://docs.lusha.com/apis/openapi/prospecting/prospectingcontacts.md): Search for contacts that match your Ideal Customer Profile using rich filter criteria.

Filter by contact attributes:
- Job title, seniority, department
- Location (city, state, country, continent)
- Existing data points (e.g. only contacts with a known work email)
- Signal activity (promotion, job change)

Filter by company attributes:
- Size, revenue, industry, technologies
- Location, intent topics, funding

Results are paginated up to 50,000 total (1,000 pages × 50 results). Use the returned contact id values with Enrich Contacts to reveal emails and phones.

> Billing: Charged per result via api_search. If signals are requested, an additional charge applies per matched signal per result.

> Persisting to a table: Pass tableId to also persist matching results into an existing table. This is additive — the primary response is unchanged, and a tableWrite object is added showing what happened on the table side. See Contacts Tables.

### Prospecting Companies

 - [POST /v3/companies/prospecting](https://docs.lusha.com/apis/openapi/prospecting/prospectingcompanies.md): Search for companies that match your target market using rich filter criteria.

Filter by:
- Size, revenue range, industry, sub-industry
- Technologies in use
- Locations (HQ country, state, city)
- SIC and NAICS codes
- Buyer intent topics
- Signal activity (headcount changes, hiring surges, news events)

Results are paginated up to 50,000 total. Use the returned company id values with Enrich Companies to get full firmographic data.

> Billing: Charged per result via api_search. If signals are requested, an additional charge applies per matched signal per result.

> Persisting to a table: Pass tableId to also persist matching results into an existing table. This is additive — the primary response is unchanged, and a tableWrite object is added showing what happened on the table side. See Companies Tables.

## Lookalikes

**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).


### Contact Lookalikes

 - [POST /v3/contacts/lookalike](https://docs.lusha.com/apis/openapi/lookalikes/getcontactlookalikes.md): Find contacts similar to a set of seed contacts using AI-powered recommendations.

Provide 5-100 seed contacts via LinkedIn URLs, emails, Lusha IDs, or name + company. The API returns contacts who share similar roles, seniority, and company profiles.

Pagination without duplicates:
On your first request, omit dedupeSessionId — the server generates one and returns it. Pass it on every subsequent request to get more results without repeating contacts already seen. Sessions are retained for 30 days.

Use the exclude field to always filter out specific contacts (e.g. existing customers).

Results are lightweight previews. Use Enrich Contacts with the returned id to get emails and phones.

> Billing: Charged per result via the lookalikeContact action.

> Persisting to a table: Pass tableId to also persist matching results into an existing table. See Contacts Tables.

### Company Lookalikes

 - [POST /v3/companies/lookalike](https://docs.lusha.com/apis/openapi/lookalikes/getcompanylookalikes.md): Find companies similar to a set of seed companies using AI-powered recommendations.

Provide 5-100 seed companies via domains or LinkedIn URLs. The API returns companies with similar size, industry, and profile.

Pagination without duplicates:
On your first request, omit dedupeSessionId — the server generates one and returns it. Pass it on every subsequent request to get more results without repeating companies already seen. Sessions are retained for 30 days.

Use the exclude field to always filter out specific companies (e.g. existing customers or competitors).

Results are lightweight previews. Use Enrich Companies with the returned id to get full firmographic data.

> Billing: Charged per result via the lookalikeCompany action.

> Persisting to a table: Pass tableId to also persist matching results into an existing table. See Companies Tables.

## Contacts Tables

**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** — 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 / List Columns / Remove Column / Remove Entities are free.
- 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).


### Create Contacts Table

 - [POST /v3/contacts/tables](https://docs.lusha.com/apis/openapi/contacts-tables/createcontactstable.md): Create a new, empty contacts table, optionally seeded with an initial list of contact IDs.

> Billing: Free.

### List Contacts Tables

 - [POST /v3/contacts/tables/list](https://docs.lusha.com/apis/openapi/contacts-tables/listcontactstables.md): List contacts tables owned by the given user, plus any tables shared with the account.

> Billing: Free.

### Get Contacts Table

 - [GET /v3/contacts/tables/{table_id}](https://docs.lusha.com/apis/openapi/contacts-tables/getcontactstable.md): Get a table's metadata and current processing status.

> Billing: Free.

### Update Contacts Table

 - [PATCH /v3/contacts/tables/{table_id}](https://docs.lusha.com/apis/openapi/contacts-tables/updatecontactstable.md): Rename a table, change its visibility, or reassign its owner. All fields except owner are optional — send only what changes.

> Billing: Free.

### Delete Contacts Table

 - [DELETE /v3/contacts/tables/{table_id}](https://docs.lusha.com/apis/openapi/contacts-tables/deletecontactstable.md): Permanently delete a table and all its data. This cannot be undone.

> Billing: Free.

### Get Contacts Table Entities

 - [GET /v3/contacts/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/contacts-tables/getcontactstableentities.md): Read a page of rows in the table, with all column values and per-cell status.

> Billing: Charged per row returned via export_api.

### Add Entities to Contacts Table

 - [POST /v3/contacts/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/contacts-tables/addcontactstableentities.md): Add up to 500 contact IDs to an existing table. entityIds accepts either the encrypted Lusha token (v{N}.…, as returned by Search/Enrich/Get Entities) or the legacy numeric personId — an ID that's neither returns 400. Already-present IDs are reported as alreadyPresent and not re-added; unresolvable IDs are not an error, they come back in invalidIds with a 200.

Optionally pass companyIds — one lushaCompanyId per contact, index-aligned with entityIds — to help pair company-level enrichment to the right company for each contact.

> Billing: Free.

### Remove Entities from Contacts Table

 - [DELETE /v3/contacts/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/contacts-tables/removecontactstableentities.md): Remove specific contact IDs from a table.

> Billing: Free.

### List Contacts Table Columns

 - [GET /v3/contacts/tables/{table_id}/columns](https://docs.lusha.com/apis/openapi/contacts-tables/listcontactstablecolumns.md): List the columns on a table, with type and aggregated per-cell status counts.

> Billing: Free.

### Remove Column from Contacts Table

 - [DELETE /v3/contacts/tables/{table_id}/columns/{column_id}](https://docs.lusha.com/apis/openapi/contacts-tables/removecontactstablecolumn.md): Remove a column and delete all of its cell data across the table. Default Lusha columns cannot be removed.

> Billing: Free.

### Run Column on Contacts Table

 - [POST /v3/contacts/tables/{table_id}/columns/{column_id}/run](https://docs.lusha.com/apis/openapi/contacts-tables/runcontactstablecolumn.md): Populate or refresh a column's data for some or all rows in the table. This is asynchronous — the call returns immediately with status: "processing"; poll Get Contacts Table for isProcessing and per-column row-status counts to know when it's done, then read the values via Get Contacts Table Entities.

runScope values:
- all — every row, including already-processed ones (re-runs / refreshes). Most expensive.
- missing — only rows that have never been run for this column. Cheapest, safe to call repeatedly.
- specific — only the entityIds you pass. Also how you implement "run for this page" — fetch the page via Get Contacts Table Entities, then pass those IDs here.

> Billing: Charged per row processed, per the column's credit tier. Re-running with all charges again for rows that already have data.

## Companies Tables

**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** — 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 / List Columns / Remove Column / Remove Entities are free.
- 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).


### Create Companies Table

 - [POST /v3/companies/tables](https://docs.lusha.com/apis/openapi/companies-tables/createcompaniestable.md): Create a new, empty companies table, optionally seeded with an initial list of company IDs.

> Billing: Free.

### List Companies Tables

 - [POST /v3/companies/tables/list](https://docs.lusha.com/apis/openapi/companies-tables/listcompaniestables.md): List companies tables owned by the given user, plus any tables shared with the account.

> Billing: Free.

### Get Companies Table

 - [GET /v3/companies/tables/{table_id}](https://docs.lusha.com/apis/openapi/companies-tables/getcompaniestable.md): Get a table's metadata and current processing status.

> Billing: Free.

### Update Companies Table

 - [PATCH /v3/companies/tables/{table_id}](https://docs.lusha.com/apis/openapi/companies-tables/updatecompaniestable.md): Rename a table, change its visibility, or reassign its owner. All fields except owner are optional — send only what changes.

> Billing: Free.

### Delete Companies Table

 - [DELETE /v3/companies/tables/{table_id}](https://docs.lusha.com/apis/openapi/companies-tables/deletecompaniestable.md): Permanently delete a table and all its data. This cannot be undone.

> Billing: Free.

### Get Companies Table Entities

 - [GET /v3/companies/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/companies-tables/getcompaniestableentities.md): Read a page of rows in the table, with all column values and per-cell status.

> Billing: Charged per row returned via export_api.

### Add Entities to Companies Table

 - [POST /v3/companies/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/companies-tables/addcompaniestableentities.md): Add up to 500 company IDs to an existing table. entityIds accepts either the encrypted Lusha token (v{N}.…, as returned by Search/Enrich/Get Entities) or the legacy numeric lushaCompanyId — an ID that's neither returns 400. Already-present IDs are reported as alreadyPresent and not re-added; unresolvable IDs are not an error, they come back in invalidIds with a 200.

> Billing: Charges reveal_company per newly-added company, deduped via row-count delta — duplicates and already-present companies aren't charged again.

### Remove Entities from Companies Table

 - [DELETE /v3/companies/tables/{table_id}/entities](https://docs.lusha.com/apis/openapi/companies-tables/removecompaniestableentities.md): Remove specific company IDs from a table.

> Billing: Free.

### List Companies Table Columns

 - [GET /v3/companies/tables/{table_id}/columns](https://docs.lusha.com/apis/openapi/companies-tables/listcompaniestablecolumns.md): List the columns on a table, with type and aggregated per-cell status counts.

> Billing: Free.

### Remove Column from Companies Table

 - [DELETE /v3/companies/tables/{table_id}/columns/{column_id}](https://docs.lusha.com/apis/openapi/companies-tables/removecompaniestablecolumn.md): Remove a column and delete all of its cell data across the table. Default Lusha columns cannot be removed.

> Billing: Free.

### Run Column on Companies Table

 - [POST /v3/companies/tables/{table_id}/columns/{column_id}/run](https://docs.lusha.com/apis/openapi/companies-tables/runcompaniestablecolumn.md): Populate or refresh a column's data for some or all rows in the table. This is asynchronous — the call returns immediately with status: "processing"; poll Get Companies Table for isProcessing and per-column row-status counts to know when it's done, then read the values via Get Companies Table Entities.

runScope values:
- all — every row, including already-processed ones (re-runs / refreshes). Most expensive.
- missing — only rows that have never been run for this column. Cheapest, safe to call repeatedly.
- specific — only the entityIds you pass. Also how you implement "run for this page" — fetch the page via Get Companies Table Entities, then pass those IDs here.

> Billing: Charged per row processed, per the column's credit tier. Company enrichment charges once per company per table — re-runs on an already-paid company in the same table are free.

## Signals

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`

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


### Contact Signals

 - [POST /v3/contacts/signals](https://docs.lusha.com/apis/openapi/signals/getcontactsignals.md): Retrieve signal events for a list of contacts — job changes and promotions.

Pass up to 100 contact ids. Use signalTypes to specify which events to return (promotion, companyChange, or allSignals). Optionally set a startDate to limit results to recent activity.

> Billing: Charged per matched signal per result via the showSignalsContact action.

> Persisting to a table: Pass tableId to also add these contacts to an existing table and populate the Signals column. See Contacts Tables.

### Company Signals

 - [POST /v3/companies/signals](https://docs.lusha.com/apis/openapi/signals/getcompanysignals.md): Retrieve signal events for a list of companies — hiring activity, headcount changes, web traffic, IT spend, and news.

Pass up to 100 company ids. Use signalTypes to specify which signals to return (or use allSignals). Optionally set a startDate to limit results to recent activity.

> Billing: Charged per matched signal per result via the showSignalsCompany action.

> Persisting to a table: Pass tableId to also add these companies to an existing table and populate the Signals column. See Companies Tables.

### Get Contact Signal Types

 - [GET /v3/contacts/signals/types](https://docs.lusha.com/apis/openapi/signals/getcontactsignaltypes.md): Returns the full list of supported signal types for contacts.

### Get Company Signal Types

 - [GET /v3/companies/signals/types](https://docs.lusha.com/apis/openapi/signals/getcompanysignaltypes.md): Returns the full list of supported signal types for companies.

### Get Company Signal Filters (Discovery)

 - [GET /v3/companies/signals/filters](https://docs.lusha.com/apis/openapi/signals/getcompanysignalfilters.md): Returns all available filter types for company signals and whether each requires a search query.

### Get Company Signal Filter Values

 - [GET /v3/companies/signals/filters/{filterType}](https://docs.lusha.com/apis/openapi/signals/getcompanysignalfiltervalues.md): Returns valid values for a single company signal filter type.

| Filter type | Query required? |
|---|---|
| newsEventTypes | No |
| hiringByDepartments | No |
| hiringByLocations | Yes (2-256 chars) |

## Decision Makers

Supply companies by domain or Lusha ID and get back the most relevant decision makers per company, ranked by fit. Results are free contact previews — pass the returned id values to Enrich Contacts to reveal emails and phones. 


### Get Decision Makers

 - [POST /v3/contacts/decision-makers](https://docs.lusha.com/apis/openapi/decision-makers/getdecisionmakers.md): Resolve each supplied company to a Lusha company ID, rank the most relevant decision makers per company using the buying-committee-ranker model, and return them grouped per company.

Results are free previews — name, title, company, location, LinkedIn, seniority, and department — with has and canReveal fields. Reveal emails and phones separately via Enrich Contacts.

Accepted company identifiers (exactly one required per entry):
- domain — resolved to a Lusha company ID server-side
- id — encrypted Lusha company ID (vN.…); legacy numeric IDs accepted during transition

## Website Visits

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


### Get Website Visitors

 - [POST /v3/companies/website-visits](https://docs.lusha.com/apis/openapi/website-visits/getwebsitevisits.md): Returns companies ranked by website-visit signals for your tracked domains and date range.

Domains must be configured for tracking in the Lusha dashboard — they are resolved to site IDs server-side. Each result combines a V3 company firmographic preview (same shape as Search Companies) with behavioral visit metrics.

Notes:
- Date range must be ≤ 3 months
- If any requested domain is not configured for tracking, the entire request fails with 400
- limit accepts 1–150

## Filters

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


### Get Contact Filter Types (Discovery)

 - [GET /v3/contacts/prospecting/filters](https://docs.lusha.com/apis/openapi/filters/getcontactfiltertypes.md): Returns all available filter types for contact prospecting and whether each requires a search query.

### Get Contact Filter Values

 - [GET /v3/contacts/prospecting/filters/{filterType}](https://docs.lusha.com/apis/openapi/filters/getcontactfiltervalues.md): Returns valid values for a single contact filter type.

| Filter type | Query required? |
|---|---|
| departments | No |
| seniority | No |
| existingDataPoints | No |
| countries | No |
| locations | Yes (2-256 chars) |

### Get Company Filter Types (Discovery)

 - [GET /v3/companies/prospecting/filters](https://docs.lusha.com/apis/openapi/filters/getcompanyfiltertypes.md): Returns all available filter types for company prospecting and whether each requires a search query.

### Get Company Filter Values

 - [GET /v3/companies/prospecting/filters/{filterType}](https://docs.lusha.com/apis/openapi/filters/getcompanyfiltervalues.md): Returns valid values for a single company filter type.

| Filter type | Query required? |
|---|---|
| sizes | No |
| revenues | No |
| sics | No |
| naics | No |
| intentTopics | No |
| industriesLabels | No |
| names | Yes (2-256 chars) |
| technologies | Yes (2-256 chars) |
| locations | Yes (2-256 chars) |

## Webhooks

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


### Create Subscription

 - [POST /api/subscriptions](https://docs.lusha.com/apis/openapi/webhooks/createsubscription.md): 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 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"
  }
  


Response Requirements

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




Field Descriptions & Implementation Guide

  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

  

----

### List Subscriptions

 - [GET /api/subscriptions](https://docs.lusha.com/apis/openapi/webhooks/listsubscriptions.md): Returns all webhook subscriptions for your account with pagination support.

Endpoint: (GET) https://api.lusha.com/api/subscriptions

Pagination:
- Results are sorted by createdAt in descending order (newest first)
- Default limit: 10, max limit: 100
- Use offset for pagination through large result sets

> Note: The webhook secret is never returned in list responses for security.

### Get Subscription by ID

 - [GET /api/subscriptions/{id}](https://docs.lusha.com/apis/openapi/webhooks/getsubscriptionbyid.md): Returns a single webhook subscription by ID.

Endpoint: (GET) https://api.lusha.com/api/subscriptions/{id}

### Update Subscription

 - [PATCH /api/subscriptions/{id}](https://docs.lusha.com/apis/openapi/webhooks/updatesubscription.md): Updates an existing webhook subscription. All fields are optional.

Endpoint: (PATCH) https://api.lusha.com/api/subscriptions/{id}

---
Reactivating Disabled Subscriptions:

When setting isActive: true on a previously disabled subscription, the system automatically:
- Clears the blockReason field
- Clears the blockedAt timestamp
- Resets the retry counter

Regenerating Secrets:

Set regenerateSecret: true to generate a new webhook secret. The new secret:
- Affects all subscriptions for your account
- Is only shown once in the response
- Immediately invalidates the old secret
---

### Test Subscription

 - [POST /api/subscriptions/{id}/test](https://docs.lusha.com/apis/openapi/webhooks/testsubscription.md): Test a webhook subscription by sending a test signal. Supports three test modes.

Endpoint: (POST) https://api.lusha.com/api/subscriptions/{id}/test
---
Test Modes:
- direct - Quick HTTP check only (validates URL responds correctly)
- kafka - Fanout handler only (tests Kafka message processing)
- full - Complete Kafka flow (default - end-to-end test)

Important Notes:
- Test deliveries do NOT consume credits
- Test payloads use mock data
- Useful for verifying webhook configuration before going live

### Delete Subscriptions

 - [POST /api/subscriptions/delete](https://docs.lusha.com/apis/openapi/webhooks/deletesubscriptions.md): Delete one or more webhook subscriptions. Returns detailed results for each deletion with partial success support.

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

---

Behavior:
- Each subscription is processed independently
- Returns detailed results for each item including deleted subscription info
- Invalid ID formats are gracefully handled and reported as NOT_FOUND
- Duplicate IDs are automatically deduplicated
- Deletion is permanent and cannot be undone

### Get Audit Logs

 - [GET /api/audit-logs](https://docs.lusha.com/apis/openapi/webhooks/getauditlogs.md): Retrieve webhook delivery logs for your account.

Endpoint: (GET) https://api.lusha.com/api/audit-logs

What's Logged:
- All webhook delivery attempts (success and failures)
- HTTP status codes and response times
- Error messages for failed deliveries
- Delivery timestamps and duration metrics

Filtering:
- Filter by subscription ID to see logs for specific subscriptions
- Filter by status to see only successes, failures, or permanent failures

Rate Limit: 100 requests/minute per account

> Note: Logs are retained for 90 days (successful) and 180 days (failed/DLQ)

### Get Audit Log Statistics

 - [GET /api/audit-logs/stats](https://docs.lusha.com/apis/openapi/webhooks/getauditlogstats.md): Get delivery statistics for your account.

Endpoint: (GET) https://api.lusha.com/api/audit-logs/stats

### Get Account Secret

 - [GET /api/account/secret](https://docs.lusha.com/apis/openapi/webhooks/getaccountsecret.md): Retrieve the current account webhook secret.

Endpoint: (GET) https://api.lusha.com/api/account/secret

### Regenerate Account Secret

 - [POST /api/account/secret/regenerate](https://docs.lusha.com/apis/openapi/webhooks/regenerateaccountsecret.md): Regenerate the account webhook secret. Affects all subscriptions for the account.

Endpoint: (POST) https://api.lusha.com/api/account/secret/regenerate

Behavior:
- If a secret already exists: Replaces with new secret (old secret is invalidated)
- If no secret exists: Creates new secret automatically

Important Notes:
- The secret is only shown once in the response. Store it securely.
- This endpoint always succeeds (upsert operation)
- Regenerating invalidates the old secret for all subscriptions (if one existed)
- An account secret must exist before webhooks can be delivered

### Create Opt-Out Subscription

 - [POST /api/subscriptions/opt-out](https://docs.lusha.com/apis/openapi/webhooks/createoptoutsubscription.md): Subscribe to real-time notifications when a contact opts out of data processing. When a contact requests removal, Lusha sends an OptOutWebhookPayload to your endpoint so you can action the removal in your own systems (CRM, outreach tools, etc.).

Endpoint: (POST) https://api.lusha.com/api/subscriptions/opt-out

---

How it works:
- Create one opt-out subscription per account (scoped to contact entity type)
- Lusha delivers a POST request to your URL whenever a contact opts out
- The payload includes the contact identity, opt-out date, and the specific data points (emails and/or phones) that must be removed

Payload you'll receive:
json
{
  "contactId": "987654321",
  "fullName": "Jane Doe",
  "companyName": "Acme Corp",
  "jobTitle": "Director of Product",
  "linkedinUrl": "https://www.linkedin.com/in/jane-doe",
  "contactOptOutDate": "2026-04-22 14:32:11.412",
  "contactExposureDate": "2025-08-03 09:15:47",
  "datapoints": [
    { "datapointId": "+14155550199", "datapointType": "phone" },
    { "datapointId": "jane.doe@acme.com", "datapointType": "email" }
  ],
  "partnerClientId": "acme-crm-tenant-42"
}


> Important: Signature verification applies the same way as standard webhook deliveries. See Security & Verification for details.

> Note: Ensure your account has a webhook secret before creating this subscription. See Regenerate Account Secret.

## Account

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


### Get Account Usage

 - [GET /v3/account/usage](https://docs.lusha.com/apis/openapi/account/getaccountusage.md): Returns a full snapshot of your account status:
- Credits — total, used, and remaining for the current billing cycle
- Rate limits — current usage and reset times for daily, hourly, and per-minute windows
- Plan — your current plan category and renewal dates
- Pricing — credit cost per action type across all public API endpoints

> Rate limit: This endpoint is limited to 5 requests per minute.

