> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Connect AI agents to LeadIQ

The LeadIQ connector lets your AI agent act in each user's LeadIQ account. Each user connects their own LeadIQ API key once, and Scalekit sends it with every call, so your agent never handles credentials. It comes with 14 tools.

**Authentication:** API Key
**Categories:** CRM & Sales, Analytics
**Tools:** 14: 11 read, 3 write, 0 destructive
**Users sign in with:** API key
**Built by:** Scalekit connector
**Try it:** [Playground in the Scalekit dashboard](https://app.scalekit.com/ws/signup?sk_intent=playground&provider=LEADIQ)

## What you can do

- **Search contacts**: look up verified work emails, direct dials, and mobile numbers by LinkedIn URL, email, or name
- **Preview before consuming credits**: check whether LeadIQ has a work email or phone for a person without spending credits
- **Enrich companies**: fetch firmographics including industry, employee count, and location by domain or name
- **Advanced prospecting**: filter contacts by title, seniority, industry, company size, and location; get results flat or grouped by company
- **Manage prospect lists**: create lists, add contacts, and retrieve saved prospects (requires Prospector plan)
- **Monitor quota**: check API credit usage, plan limits, and subscription status before making credit-consuming calls

## Setup

1. ### Install the SDK

   **Node.js**

   ```bash
   npm install @scalekit-sdk/node dotenv
   ```

   **Python**

   ```bash
   pip install scalekit-sdk-python python-dotenv
   ```

2. ### Set your credentials

   Add your Scalekit credentials to your `.env` file. Find values in **[app.scalekit.com](https://app.scalekit.com)** > **Developers** > **API Credentials**.

   ```sh title=".env"
   SCALEKIT_ENVIRONMENT_URL=<your-environment-url>
   SCALEKIT_CLIENT_ID=<your-client-id>
   SCALEKIT_CLIENT_SECRET=<your-client-secret>
   ```

3. ### Create the LeadIQ connection

   In **AgentKit > Connections**, create a LeadIQ connection. The name you give it is the `connection_name` your code passes. See [Configure connections](/agentkit/connections/).

   **Console steps with screenshots:**

   Register your LeadIQ API key with Scalekit so it stores it securely and injects it into every request. LeadIQ uses API key authentication.

   1. ### Get your LeadIQ API key

      - Sign in to [LeadIQ](https://app.leadiq.com) and go to **Settings** → **API Keys**.
      - Copy the **Secret API key** value, or click **Generate new API key** to create one dedicated to this integration.

      > Image: LeadIQ Settings API Keys page showing Secret API key and Secret Base64 API key fields

      > tip: Store the key securely
      >
      > LeadIQ API keys have full account access. Store the key in a secrets manager and never hard-code it in your application source code.

   2. ### Create a connection in Scalekit

      - In [Scalekit dashboard](https://app.scalekit.com), go to **AgentKit** → **Connections** → **Create Connection**. Find **LeadIQ** and click **Create**.
      - Note the **Connection name** — you will use this as `connection_name` in your code (e.g., `leadiq`).
      - Click **Save**.

   3. ### Add a connected account

      Connected accounts link a specific user identifier in your system to their LeadIQ API key. Add one in the dashboard to test. In production, each user adds their own through the authorization link: they enter their credentials on the page it opens.

      **In the dashboard, to test**

      - Open the connection you created and click the **Connected Accounts** tab → **Add account**.
      - Fill in:
        - **Your User's ID** — a unique identifier for this user in your system (e.g., `user_123`)
        - **API Key** — the LeadIQ API key from step 1
      - Click **Create Account**.

      **From your backend, if your app already has the credentials**

      For example, when users enter them on a settings page in your app:

        **Node.js**

        ```typescript
        import { Scalekit, ConnectorStatus } from '@scalekit-sdk/node';

        const scalekit = new Scalekit(
          process.env.SCALEKIT_ENVIRONMENT_URL,
          process.env.SCALEKIT_CLIENT_ID,
          process.env.SCALEKIT_CLIENT_SECRET,
        );

        // Never hard-code credentials — read from secure storage or user input
        const leadiqApiKey = getUserLeadIQApiKey(); // retrieve from your secure store

        const authorizationDetails = {
          details: {
            case: 'staticAuth',
            value: {
              details: {
                username: leadiqApiKey,
              },
            },
          },
        };

        let { connectedAccount } = await scalekit.actions.upsertConnectedAccount({
          connectionName: 'leadiq',
          identifier: 'user_123',
          authorizationDetails,
        });

        // Make sure the account is ACTIVE before the first tool call.
        if (connectedAccount?.status !== ConnectorStatus.ACTIVE) {
          ({ connectedAccount } = await scalekit.actions.upsertConnectedAccount({
            connectionName: 'leadiq',
            identifier: 'user_123',
            authorizationDetails,
          }));
        }
        ```

        **Python**

        ```python
        import os
        from scalekit import ScalekitClient

        scalekit_client = ScalekitClient(
            env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"],
            client_id=os.environ["SCALEKIT_CLIENT_ID"],
            client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
        )

        # Never hard-code credentials — read from secure storage or user input
        leadiq_api_key = get_user_leadiq_api_key()  # retrieve from your secure store

        authorization_details = {"static_auth": {"username": leadiq_api_key}}

        response = scalekit_client.actions.upsert_connected_account(
            connection_name="leadiq",
            identifier="user_123",
            authorization_details=authorization_details,
        )

        # Make sure the account is ACTIVE before the first tool call.
        if response.connected_account.status != "ACTIVE":
            response = scalekit_client.actions.upsert_connected_account(
                connection_name="leadiq",
                identifier="user_123",
                authorization_details=authorization_details,
            )
        ```

## Tools

Pass the exact name to `execute_tool`, with an input like each tool's example. To ask for a tool that's missing, use the [request form](https://scalekitsupport.portal.usepylon.com/forms/request-a-connector-tool).

**Node.js**

```typescript
const result = await actions.executeTool({
  toolName: 'leadiq_flat_advanced_search',
  toolInput: {},
  connector: 'leadiq',
  identifier: 'user_123',
})
```

**Python**

```python
result = actions.execute_tool(
    tool_name="leadiq_flat_advanced_search",
    tool_input={},
    connection_name="leadiq",
    identifier="user_123",
)
```

`result.data` is the app's response as JSON, and `result.execution_id` (`executionId` in Node.js) is the ID of the call.

### `leadiq_flat_advanced_search`

Advanced People Search · Read-only

Search across LeadIQ's full contact database using advanced filters for title, seniority, company, industry, location, and more. Returns a flat list of matching contacts. Consumes credits per result.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `company_excluded_filter` (`object`, optional): Exclude contacts at companies matching these criteria
- `company_filter` (`object`, optional): Filter by company attributes including name, domain, industry, size, and location
- `contact_excluded_filter` (`object`, optional): Exclude contacts matching these criteria
- `contact_filter` (`object`, optional): Filter contacts by title, seniority, role, location, and more
- `limit` (`integer`, optional): Maximum number of contacts to return (default 10)
- `skip` (`integer`, optional): Number of results to skip for pagination (default 0)

Example input: `{}`

### `leadiq_get_account`

Get Account · Read-only

Retrieve the current LeadIQ account details including active plans, product subscriptions, billing status, and credit usage (available and used). Use this to check remaining search credits before making enrichment calls.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs: none.

Example input: `{}`

### `leadiq_get_company`

Get Company · Read-only

Retrieve a single company record by its LeadIQ company ID, returning full firmographic details: industry, employee count, headquarters location, funding, and known email domains. Use Search Company, or the company objects embedded in People Search / Advanced Search results, to find a company ID first.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `id` (`string`, required): LeadIQ company ID to retrieve

Example input: `{"id":"<id>"}`

### `leadiq_get_list`

Get Prospect List · Read-only

Retrieve a specific prospect list by ID, including its contacts with name, title, company, email, and LinkedIn URL. Use Get Prospect Lists first to find the list ID.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `id` (`string`, required): ID of the prospect list to retrieve
- `prospects_cursor` (`string`, optional): Pagination cursor from a previous response to get the next batch of prospects
- `prospects_limit` (`integer`, optional): Maximum number of prospects to return from the list (default 25)

Example input: `{"id":"<id>"}`

### `leadiq_get_lists`

Get Prospect Lists · Read-only

Retrieve all prospect lists in the LeadIQ account. Returns list metadata including name, status, and timestamps. Use the returned list IDs with Get Prospect List to fetch contacts.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `cursor` (`string`, optional): Pagination cursor from a previous response's nextCursor field
- `limit` (`integer`, optional): Maximum number of lists to return per page

Example input: `{}`

### `leadiq_get_prospect`

Get Prospect · Read-only

Retrieve a single prospect record by ID, including full contact details: emails, phones, LinkedIn, title, company, and location.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `id` (`string`, required): ID of the prospect to retrieve

Example input: `{"id":"<id>"}`

### `leadiq_get_usage`

Get Usage · Read-only

Retrieve API credit usage for the current billing period — plan credit counts, usage caps, trial usage, and subscription status. Use this to monitor quota before making credit-consuming calls.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs: none.

Example input: `{}`

### `leadiq_grouped_advanced_search`

Advanced Search Grouped by Company · Read-only

Search LeadIQ's contact database with advanced filters and get results grouped by company. Each result contains a company record with its top matching contacts. Useful for account-based prospecting. Consumes credits per contact returned.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `company_excluded_filter` (`object`, optional): Exclude companies matching these criteria
- `company_filter` (`object`, optional): Filter by company name, domain, industry, size, location, and more
- `contact_excluded_filter` (`object`, optional): Exclude contacts matching these criteria
- `contact_filter` (`object`, optional): Filter contacts by title, seniority, role, location, and more
- `limit` (`integer`, optional): Maximum number of companies to return (default 10)
- `limit_per_company` (`integer`, optional): Maximum number of contacts to return per company (default 5)
- `skip` (`integer`, optional): Number of companies to skip for pagination (default 0)

Example input: `{}`

### `leadiq_search_company`

Search Company · Read-only

Search for a company by name, domain, or LinkedIn URL. Returns firmographic data including employee count, industry, headquarters location, and funding information.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `domain` (`string`, optional): Company website domain
- `linkedin_id` (`string`, optional): LinkedIn company numeric ID
- `linkedin_url` (`string`, optional): LinkedIn company page URL
- `name` (`string`, optional): Company name to search for
- `strict` (`boolean`, optional): Enable strict matching — only return exact name or domain matches

Example input: `{}`

### `leadiq_search_people`

Search People · Read-only

Search for a person by LinkedIn URL, email, or name + company. At least one of: linkedin_url, email, or first_name+last_name must be provided. Returns verified work emails, direct dials, and current job details. Consumes LeadIQ credits per result.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `company_domain` (`string`, optional): Domain of the person's current company
- `company_name` (`string`, optional): Current company name of the person
- `contains_work_contact_info` (`boolean`, optional): Only return results that have at least one work email or work phone
- `email` (`string`, optional): Known email address of the person
- `first_name` (`string`, optional): First name of the person to search for
- `full_name` (`string`, optional): Full name of the person (alternative to first_name + last_name)
- `last_name` (`string`, optional): Last name of the person to search for
- `limit` (`integer`, optional): Maximum number of results to return (default 10, max 25)
- `linkedin_url` (`string`, optional): LinkedIn profile URL of the person
- `skip` (`integer`, optional): Number of results to skip for pagination (default 0)

Example input: `{}`

### `leadiq_search_people_preview`

Search People Preview · Read-only

Check whether LeadIQ has a work email or phone number for a person without consuming credits. Use this before calling Search People to avoid wasting credits on contacts with no data.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `company_domain` (`string`, optional): Domain of the person's current company
- `company_name` (`string`, optional): Current company name of the person
- `email` (`string`, optional): Known email address of the person
- `first_name` (`string`, optional): First name of the person
- `full_name` (`string`, optional): Full name of the person
- `last_name` (`string`, optional): Last name of the person
- `linkedin_url` (`string`, optional): LinkedIn profile URL of the person

Example input: `{}`

### `leadiq_add_prospect_to_list`

Add Prospect to List · Write

Add a contact to an existing LeadIQ prospect list. Provide first name, last name, and any known contact details. Use Get Prospect Lists to find the list ID.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `first_name` (`string`, required): First name of the prospect
- `last_name` (`string`, required): Last name of the prospect
- `list_id` (`string`, required): ID of the prospect list to add the contact to
- `company` (`string`, optional): Current company name of the prospect
- `company_domain` (`string`, optional): Website domain of the prospect's company
- `company_industry` (`string`, optional): Industry of the prospect's company
- `linkedin_url` (`string`, optional): LinkedIn profile URL of the prospect
- `mobile_phone` (`string`, optional): Mobile phone number of the prospect
- `notes` (`string`, optional): Internal notes about this prospect
- `seniority` (`string`, optional): Seniority level of the prospect
- `title` (`string`, optional): Job title of the prospect
- `work_email` (`string`, optional): Work email address of the prospect
- `work_phone` (`string`, optional): Work phone number of the prospect

Example input: `{"first_name":"<first_name>","last_name":"<last_name>","list_id":"<list_id>"}`

### `leadiq_create_list`

Create Prospect List · Write

Create a new prospect list in LeadIQ to organize contacts for outreach campaigns. Returns the created list ID for use with Add Prospect to List.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `name` (`string`, required): Name of the prospect list
- `description` (`string`, optional): Optional description of the prospect list

Example input: `{"name":"<name>"}`

### `leadiq_submit_person_feedback`

Submit Person Feedback · Write

Report incorrect or outdated contact data back to LeadIQ to improve data quality. Mark an email or phone as correct or invalid, and optionally provide a correction or bounce reason.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `value` (`string`, required): The contact info value being reported (email address or phone number)
- `company_domain` (`string`, optional): Company domain for additional context
- `company_name` (`string`, optional): Company name for additional context
- `invalid_reason` (`string`, optional): Specific bounce or invalidity reason code (for invalid emails)
- `linkedin_url` (`string`, optional): LinkedIn URL of the person the feedback is about
- `person_id` (`string`, optional): LeadIQ person ID associated with the contact info
- `status` (`string`, optional): Whether the contact info is correct or invalid. One of: `Correct`, `Invalid`.
- `title` (`string`, optional): Job title of the person at the time the contact info was used
- `type` (`string`, optional): Type of contact information being reported

Example input: `{"value":"<value>"}`

## Workflows

**Check credit quota before searching**

Always check available credits before calling tools that consume them (`leadiq_search_people`, `leadiq_flat_advanced_search`, `leadiq_grouped_advanced_search`).

  **Node.js**

  ```typescript
  const usage = await actions.executeTool({
    toolName: 'leadiq_get_usage',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {},
  });
  console.log(usage.data?.usage);
  ```

  **Python**

  ```python
  usage = actions.execute_tool(
      tool_name="leadiq_get_usage",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={},
  )
  print(usage.data)
  ```

**Preview contact availability before consuming credits**

Use `leadiq_search_people_preview` to check whether LeadIQ has a work email or phone for a person before calling `leadiq_search_people`. The preview call does not consume credits.

  **Node.js**

  ```typescript
  const preview = await actions.executeTool({
    toolName: 'leadiq_search_people_preview',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      linkedin_url: 'https://www.linkedin.com/in/janedoe',
    },
  });

  if (preview.data?.data?.searchPeoplePreview?.hasEmail) {
    // Safe to call leadiq_search_people — credits will be consumed
  }
  ```

  **Python**

  ```python
  preview = actions.execute_tool(
      tool_name="leadiq_search_people_preview",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={"linkedin_url": "https://www.linkedin.com/in/janedoe"},
  )

  result = preview.data.get("data", {}).get("searchPeoplePreview", {})
  if result.get("hasEmail"):
      # Safe to call leadiq_search_people — credits will be consumed
      pass
  ```

**Look up a contact by LinkedIn URL, email, or name**

  **Node.js**

  ```typescript
  // By LinkedIn URL (most precise)
  const contact = await actions.executeTool({
    toolName: 'leadiq_search_people',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      linkedin_url: 'https://www.linkedin.com/in/janedoe',
      limit: 1,
    },
  });

  // By name + company
  const byName = await actions.executeTool({
    toolName: 'leadiq_search_people',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      first_name: 'Jane',
      last_name: 'Doe',
      company_name: 'Acme Corp',
      limit: 5,
    },
  });
  ```

  **Python**

  ```python
  # By LinkedIn URL (most precise)
  contact = actions.execute_tool(
      tool_name="leadiq_search_people",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={
          "linkedin_url": "https://www.linkedin.com/in/janedoe",
          "limit": 1,
      },
  )

  # By name + company
  by_name = actions.execute_tool(
      tool_name="leadiq_search_people",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={
          "first_name": "Jane",
          "last_name": "Doe",
          "company_name": "Acme Corp",
          "limit": 5,
      },
  )
  ```

**Enrich a company by domain or name**

  **Node.js**

  ```typescript
  const company = await actions.executeTool({
    toolName: 'leadiq_search_company',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      domain: 'acme.com',
    },
  });
  console.log(company.data?.data?.searchCompany);
  ```

  **Python**

  ```python
  company = actions.execute_tool(
      tool_name="leadiq_search_company",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={"domain": "acme.com"},
  )
  print(company.data)
  ```

**Advanced people search with industry and seniority filters**

Pass filter objects as Python dicts or JavaScript objects — not JSON-encoded strings.

  **Node.js**

  ```typescript
  const results = await actions.executeTool({
    toolName: 'leadiq_flat_advanced_search',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      company_filter: {
        industries: ['Software Development'],
        sizes: [{ min: 50, max: 500 }],
      },
      contact_filter: {
        seniorities: ['VP', 'Director'],
      },
      limit: 10,
    },
  });
  const people = results.data?.data?.flatAdvancedSearch?.people ?? [];
  ```

  **Python**

  ```python
  results = actions.execute_tool(
      tool_name="leadiq_flat_advanced_search",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={
          "company_filter": {
              "industries": ["Software Development"],
              "sizes": [{"min": 50, "max": 500}],
          },
          "contact_filter": {
              "seniorities": ["VP", "Director"],
          },
          "limit": 10,
      },
  )
  people = results.data.get("data", {}).get("flatAdvancedSearch", {}).get("people", [])
  ```

**Advanced search grouped by company (account-based prospecting)**

Returns results organized by company, each with a list of matching contacts. Useful for account-based outreach.

  **Node.js**

  ```typescript
  const grouped = await actions.executeTool({
    toolName: 'leadiq_grouped_advanced_search',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      company_filter: {
        industries: ['Financial Services'],
        sizes: [{ min: 200, max: 5000 }],
      },
      contact_filter: {
        seniorities: ['Executive', 'VP'],
      },
      limit: 5,            // number of companies
      limit_per_company: 3, // contacts per company
    },
  });
  const companies = grouped.data?.data?.groupedAdvancedSearch?.companies ?? [];
  ```

  **Python**

  ```python
  grouped = actions.execute_tool(
      tool_name="leadiq_grouped_advanced_search",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={
          "company_filter": {
              "industries": ["Financial Services"],
              "sizes": [{"min": 200, "max": 5000}],
          },
          "contact_filter": {
              "seniorities": ["Executive", "VP"],
          },
          "limit": 5,             # number of companies
          "limit_per_company": 3, # contacts per company
      },
  )
  companies = (
      grouped.data.get("data", {})
      .get("groupedAdvancedSearch", {})
      .get("companies", [])
  )
  ```

**Report incorrect contact data**

Help improve LeadIQ data quality by reporting bounced emails or wrong phone numbers.

  **Node.js**

  ```typescript
  await actions.executeTool({
    toolName: 'leadiq_submit_person_feedback',
    connector: 'leadiq',
    identifier: 'user_123',
    toolInput: {
      value: 'jane.doe@acme.com',
      status: 'Invalid',
      type: 'WorkEmail',
      invalid_reason: 'EmailBounceCode550',
    },
  });
  ```

  **Python**

  ```python
  actions.execute_tool(
      tool_name="leadiq_submit_person_feedback",
      connection_name="leadiq",
      identifier="user_123",
      tool_input={
          "value": "jane.doe@acme.com",
          "status": "Invalid",
          "type": "WorkEmail",
          "invalid_reason": "EmailBounceCode550",
      },
  )
  ```

> note: Prospect list tools require a paid plan
>
> The `leadiq_get_lists`, `leadiq_get_list`, `leadiq_create_list`, and `leadiq_add_prospect_to_list` tools require a LeadIQ Prospector plan. On Freemium accounts these tools return a 401 from the prospector service.

## Related

Other ways to connect LeadIQ:

- [MCP server](/agentkit/connectors/leadiqmcp/): Vendor MCP, OAuth, 16 tools

Other CRM & Sales connectors ([all 64](/agentkit/connectors/?category=crm-sales)):

- [HubSpot](/agentkit/connectors/hubspot/): Scalekit connector, OAuth, 457 tools
- [Salesforce](/agentkit/connectors/salesforce/): Scalekit connector, OAuth, 74 tools
- [Close](/agentkit/connectors/close/): Scalekit connector, OAuth, 103 tools


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
