# Decision-Maker Finder – People & Emails by Company & Title (`inovaflow/decision-maker-finder`) Actor

Find the people to contact at any list of companies — by job title, seniority and department — with name, title, public profile URL, location and a work e-mail (pattern-matched, mail-server checked). Input: company names, domains or a company list. No login, no cookies. Dataset-only, MCP-ready.

- **URL**: https://apify.com/inovaflow/decision-maker-finder.md
- **Developed by:** [inovaflow](https://apify.com/inovaflow) (community)
- **Categories:** Lead generation, Business, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 decision makers

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**Find the people to contact at any list of companies — by job title, seniority and department — and get back a row per person with name, current title, public profile URL, location and a work e-mail, keyed to the company's domain.** Give it company names, domains or the rows of a company list, tell it which titles you sell to (`CEO`, `VP of Sales`, `Head of Marketing`, `CRO`, `RevOps`…), and every matching person comes back classified by **seniority** (founder, C-level, VP, director, head, manager) and **department** (sales, marketing, engineering, product, finance, people…), with the address pattern the company uses and what the mail server confirmed.

People data on the market is either a stale database dump resold by the thousand or a raw people-search wrapper that needs your login and hands you every namesake and former employee. This Actor works the way a good SDR does: it looks each company up in public sources, keeps only people whose **current** role is at that company, matches your target titles in every phrasing, and shows its work on every row.

### Decision-maker finder: what you get

One row per person:

| Field | What it tells you |
| --- | --- |
| `name`, `firstName`, `lastName` | The person, split for merge fields |
| `title`, `headline`, `seniority`, `department`, `matchedTitle` | Current title at the company, the full public headline, the derived level and function, and which of your titles it matched |
| `linkedinUrl`, `location` | Public profile URL and location |
| `company`, `companyDomain`, `companyWebsite`, `companyLinkedinUrl` | The company — `companyDomain` is the key to join back to your company list |
| `email`, `emailPattern`, `emailConfidence`, `emailVerified`, `emailVerification`, `catchAll`, `emailCandidates[]` | The most likely work address, how it was formed (`first.last`, `flast`, …), a 0–100 confidence, whether the mailbox was confirmed, what exactly was checked (`smtp-valid`, `smtp-catch-all`, `mx-only`, `no-mx`), and the alternatives |
| `sources[]`, `sourceUrl`, `snippet` | Where the person was found (`profile-search`, `website`) and the evidence |

Three dataset views: **People** (one line per person), **E-mails** (pattern, confidence, verification, candidates), **Targeting** (seniority, department, matched title).

### How people are found

1. **Public profile search** — web search over public professional profiles for each company and each of your title phrasings. A result counts only when the *current* role names the company: people who merely mention it, worked there before ("ex-", "former") or share its name are dropped.
2. **Company website** — the team, about and leadership pages are read for named executives with titles (and for e-mail addresses that reveal the company's address pattern).
3. **Classification** — seniority and department are derived from the title by rules, deterministically; your `titles`, `seniorities` and `departments` filter the result; `maxPeoplePerCompany` keeps the most senior / best-matching people.
4. **Work e-mail** — the company's address pattern is learned from addresses on its site, candidates are generated from the person's name, and each is checked against the domain's mail server; where the network allows an SMTP mailbox check, `emailVerified` becomes true. Otherwise the best pattern candidate is delivered with its confidence and `emailVerification: mx-only` — never presented as verified.

No login, no cookies, no third-party people database, no nested scrapers.

### Chain it into a prospecting pipeline

- **In:** the output of a company finder (rows with `name`, `domain`, `linkedinUrl`) can be passed as `companies` unchanged — or a list of domains from a tech-stack lookup or a hiring-signals run.
- **Out:** rows keyed by `companyDomain` with `firstName` / `lastName` / `email`, ready for an e-mail finder & verifier (to confirm or widen the addresses) and for a sequencer.

### Who uses it

- **Outbound / GTM agents** — a keyword-discoverable, MCP-callable step that turns a company list into people to write to, unattended.
- **SDR teams** — the three personas you sell to at every target account, with seniority and department already labeled.
- **Recruiters and partnership teams** — the heads of a function across a list of companies.
- **Data teams** — a people-enrichment step that joins back to the company row by domain.

### Set it up in a minute

1. Paste **Companies** (domains, names or profile URLs — one per line).
2. Enter the **Titles to find** (or leave empty for the decision makers at each company) and set **Max people per company**.
3. Start. Rows arrive as each company is finished; the run summary is in the `OUTPUT` record.

Targeting, e-mail enrichment, sources and performance settings are collapsed below the essentials; the defaults are tuned for unattended runs.

### Use it from an agent or the API

```json
{ "companies": ["lemlist.com", "gong.io"], "titles": ["CEO", "VP of Sales", "Head of Marketing"], "maxPeoplePerCompany": 5 }
```

```json
{ "companies": [{ "name": "Gong", "domain": "gong.io", "linkedinUrl": "https://www.linkedin.com/company/gong-io" }], "seniorities": ["founder", "c-level", "vp"], "departments": ["sales", "marketing"] }
```

Agents may also pass `domains`, `websites` or `urls`, and `title` / `roles` for the titles. Results are in the default dataset (`?view=people`, `?view=emails`, `?view=targeting`); the run summary (people found and filtered, searches, e-mail stats) is in the `OUTPUT` record of the run's key-value store. Through the Apify MCP server, call `inovaflow/decision-maker-finder` with the same input.

### Output example

```json
{
  "name": "Jessie Sloan",
  "firstName": "Jessie",
  "lastName": "Sloan",
  "title": "VP, Corporate Revenue Unit",
  "headline": "VP, Corporate Revenue Unit @ Gong",
  "seniority": "vp",
  "department": "sales",
  "matchedTitle": "VP of Sales",
  "linkedinUrl": "https://www.linkedin.com/in/jessie-sloan-440230a1",
  "location": "Atlanta, Georgia, United States",
  "company": "Gong",
  "companyDomain": "gong.io",
  "email": "jessie.sloan@gong.io",
  "emailPattern": "first.last",
  "emailConfidence": 70,
  "emailVerified": false,
  "emailVerification": "mx-only",
  "catchAll": null,
  "emailCandidates": [{ "address": "jessie.sloan@gong.io", "pattern": "first.last", "confidence": 70, "verified": false, "verification": "mx-only" }, { "address": "jessie@gong.io", "pattern": "first", "confidence": 35, "verified": false, "verification": "mx-only" }],
  "sources": ["profile-search"]
}
```

### Pricing

Pay per event: **$0.02 per decision maker** delivered and **$0.01 per company searched**, plus a small per-run start fee. Duplicates and people your filters remove are never charged; a company is charged once when it was actually searched, whether or not anyone matched — a 100-company run capped at 5 people each costs at most $11.

### Good to know

- **E-mail verification depth depends on the network.** Where outbound SMTP is blocked, addresses are verified down to the domain's mail server (`mx-only`) and delivered with a pattern confidence; where SMTP is reachable, mailboxes are confirmed (`smtp-valid`) and catch-all domains are flagged.
- **Companies with a common-word name** (`Clay`, `Gong`) work because a person is accepted only when the company appears in their current role; pass the domain too for the best precision.
- **Coverage per company** is a few search pages deep by default (`maxSearchesPerCompany`, retries included); raise it for big companies and broad title lists.
- **Runs stop early when they would only waste time.** If the search backend is unavailable, or nobody matches at the first ten companies searched, the run stops with a status message saying why; the companies it did not reach are never charged. Set `stopWhenNothingMatches` to false for lists where most companies are expected to have nobody.
- Results reflect what people publish about themselves; `sources[]` and `snippet` carry the evidence for every row.

# Actor input Schema

## `companies` (type: `array`):

One per line: a domain (`gong.io`), a company name (`Syberry`, or `Syberry, Austin TX`) or a company profile URL. Also accepted: the rows of a company list as objects {name, domain, linkedinUrl} — e.g. the output of a company finder — and the aliases `domains`, `websites`, `urls`.

## `titles` (type: `array`):

Job titles or keywords, one per line — abbreviations are understood (`CEO`, `VP Sales`, `Head of Marketing`, `CRO`, `RevOps`). Each is matched against the person's current title in every common phrasing ("VP of Sales", "Vice President, Sales"…). Leave empty to get the decision makers at each company (founders, C-level, VPs, heads, directors).

## `maxPeoplePerCompany` (type: `integer`):

Cap on delivered people per company (highest seniority and best title match first). Also caps what you pay.

## `seniorities` (type: `array`):

Keep only these levels. Empty = any.

## `departments` (type: `array`):

Keep only these departments. Empty = any.

## `maxSearchesPerCompany` (type: `integer`):

How many search-engine result pages one company may use, retries included (a page holds up to ten profiles; one page per title group and result page). More pages = more coverage for big companies and broad title lists.

## `findEmails` (type: `boolean`):

Add `email`, `emailPattern`, `emailConfidence`, `emailVerified`, `emailVerification` and up to four `emailCandidates` per person. Needs the company domain (given, or found on its profile / website).

## `verifyEmails` (type: `boolean`):

Check syntax and the domain's mail server (MX) for every candidate; domains without a mail server yield no e-mail.

## `smtpVerification` (type: `boolean`):

Also ask the mail server whether the mailbox exists (and detect catch-all domains) where the network allows it; falls back to the mail-server check otherwise.

## `useProfileSearch` (type: `boolean`):

Find people through web search over public professional profiles (name, current title, location, profile URL). Uses Apify's Google search proxy, a few requests per company.

## `useWebsite` (type: `boolean`):

Read the company's team / about / leadership pages for named executives with titles (free, direct fetch). Also the source of the domain's e-mail pattern.

## `maxCompanies` (type: `integer`):

Upper bound on companies processed in one run.

## `countryCode` (type: `string`):

Two-letter country code for the profile search edition (us, gb, de, …).

## `language` (type: `string`):

Two-letter language code for the profile search.

## `maxConcurrency` (type: `integer`):

How many companies are processed at once.

## `stopWhenNothingMatches` (type: `boolean`):

Stop the run early when the first 10 companies searched deliver nobody — usually wrong company names / domains or too narrow title, seniority or department filters — instead of searching the whole list. Turn off for sparse lists where most companies are expected to have nobody.

## Actor input object example

```json
{
  "companies": [
    "syberry.com",
    "https://www.linkedin.com/company/stripe",
    "Clay, New York"
  ],
  "titles": [
    "CTO",
    "Head of People",
    "Revenue Operations"
  ],
  "maxPeoplePerCompany": 10,
  "seniorities": [],
  "departments": [],
  "maxSearchesPerCompany": 6,
  "findEmails": true,
  "verifyEmails": true,
  "smtpVerification": true,
  "useProfileSearch": true,
  "useWebsite": true,
  "maxCompanies": 200,
  "countryCode": "us",
  "language": "en",
  "maxConcurrency": 6,
  "stopWhenNothingMatches": true
}
```

# Actor output Schema

## `people` (type: `string`):

One row per person: name, title, seniority, department, company, profile URL, location, e-mail.

## `emails` (type: `string`):

The work e-mail per person with pattern, confidence and verification.

## `targeting` (type: `string`):

Seniority, department and which of your titles each person matched.

## `summary` (type: `string`):

Counts, filters and enrichment stats.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "lemlist.com",
        "gong.io"
    ],
    "titles": [
        "CEO",
        "VP of Sales",
        "Head of Marketing"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/decision-maker-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "lemlist.com",
        "gong.io",
    ],
    "titles": [
        "CEO",
        "VP of Sales",
        "Head of Marketing",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/decision-maker-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "lemlist.com",
    "gong.io"
  ],
  "titles": [
    "CEO",
    "VP of Sales",
    "Head of Marketing"
  ]
}' |
apify call inovaflow/decision-maker-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,inovaflow/decision-maker-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/I2fiifAMOfrBKVCW0/builds/XCKJjo6obcuXRwhLH/openapi.json
