# Hiring Manager Contacts - Who's Hiring Behind Any Job Posting (`hirebase/hiring-manager-contacts`) Actor

Turn a job posting into the likely hiring managers and recruiters behind it: name, role and LinkedIn profile, researched per posting. About 3 in 4 postings return contacts, typically 5-10 each. Paste job IDs from any Hirebase job scraper. Business contacts only.

- **URL**: https://apify.com/hirebase/hiring-manager-contacts.md
- **Developed by:** [Hirebase](https://apify.com/hirebase) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

## Hiring Manager Contacts - Who's Hiring Behind Any Job Posting

Paste job postings in, get the **likely hiring managers and recruiters behind them** out: name, role and LinkedIn profile, researched posting by posting. Built on [Hirebase](https://www.hirebase.org), whose research agent reads the posting, the employer's career page and public professional profiles to work out who owns the role.

A job posting is a buying signal with no name on it. This actor puts the names on.

**What to expect - measured on 100 real postings across 10 job categories:**

- **About 3 in 4 postings return contacts** (75 of 100). The rest come back empty or fail on Hirebase's side, and are never charged.
- **Typically 5-10 contacts per posting** (median 8): the recruiter or talent partner on the role, the team's managers and leads, and department heads or executives.
- **Every contact had a name, role and LinkedIn profile.** Email addresses are returned only when Hirebase finds one, which in this sample was never - treat this as a LinkedIn-first dataset.
- **It takes time.** Each posting is researched live in the background. Expect minutes for a handful of postings and hours for a large batch (see *How long does it take?*).

These are **likely** contacts: people whose public role at the employer makes them the probable owner of the posting, not a confirmed named contact from the job ad. Business contact details only - name, job title, LinkedIn profile and, when found, work email. No phone numbers or personal data.

**Why this actor?**

- 🎯 **Per posting, not per company** - contacts are matched to the specific role, so an iOS engineering posting returns the iOS engineering managers, not a generic HR inbox.
- 🧑‍💼 **Typed contacts** - each row is tagged `recruiter`, `hiringManager`, `leadership` or `hr`, so you can route recruiters to one sequence and hiring managers to another.
- 🔗 **Chains from every Hirebase scraper** - feed it the `id` column from Job Search, Fresh Jobs Feed, AI Job Search, any ATS scraper, or the sample postings from Company Search.
- 💸 **Pay only for contacts found** - postings that return nothing cost nothing, and a re-run never charges twice for the same posting.
- ⏱ **Resumable** - if a run stops before the research is done, run it again with the same IDs and it collects the results.

### How to use it

1. Run any Hirebase job scraper and copy the `id` values of the postings you care about.
2. Paste them into **Job IDs**, one per line. Entries that aren't a job ID are skipped with a warning.
3. Set **Max postings** - start with 5-10 to see the results, then scale up.
4. Run. Rows appear in the dataset as each posting finishes.

### Example input

```json
{
  "jobIds": [
    "6ab12dde712f8e0e0ea07739",
    "6ab130766a7163d04dca4d94"
  ],
  "maxJobs": 10,
  "maxWaitMinutes": 55
}
```

### Output

One row per likely contact, with the posting it was found for on every row. Real rows from a Senior iOS Engineer posting at Notability:

```json
[
  {
    "name": "Drew Bratcher",
    "role": "iOS Engineering Manager",
    "contactType": "hiringManager",
    "employer": null,
    "linkedinUrl": "https://www.linkedin.com/in/drew-bratcher-b8a9283a",
    "email": null,
    "photoUrl": null,
    "rank": 2,
    "jobId": "6ab12dde712f8e0e0ea07739",
    "jobTitle": "Senior iOS Engineer",
    "companyName": "Notability",
    "companySlug": "ginger-labs",
    "applicationLink": "https://job-boards.greenhouse.io/gingerlabsinc/jobs/5429798008",
    "jobLocation": "San Francisco",
    "datePosted": "2026-09-21"
  },
  {
    "name": "Garrett Mitchell",
    "role": "CTO",
    "contactType": "leadership",
    "linkedinUrl": "https://www.linkedin.com/in/garrettm7",
    "rank": 3,
    "jobTitle": "Senior iOS Engineer",
    "companyName": "Notability"
  }
]
```

`employer` is the company named in the contact's own role line (e.g. *"Talent Acquisition Lead at B\&Q"*). It is usually the same as `companyName`; when it differs, the research found the posting really belongs to another employer - a handful of postings in the Hirebase index are attributed to the wrong company, and the contacts follow the true one.

Export to JSON, CSV or Excel, or pipe into Clay, HubSpot, Salesforce, Make, n8n, Zapier or Google Sheets.

### Great for

- **Outbound sales** - a company opening roles in your category is staffing up; now you know who to write to.
- **Recruiting and staffing agencies** - reach the hiring manager and the internal recruiter on a live requisition.
- **Job seekers** - find the people to message about a role instead of applying into the void.
- **Account research** - map who runs a function at a target account from the roles they are hiring for.

### How long does it take?

Hirebase researches each posting individually, and processes roughly a dozen postings an hour for this actor. A few postings usually finish within minutes to an hour; a batch of 25 can take several hours, and the full 100 most of a day.

The actor saves each posting's contacts as soon as they are ready, and keeps waiting up to **Wait up to (minutes)** - 55 by default, to fit Apify's standard 1-hour run timeout. For bigger batches, raise both the wait and the run timeout (under *Run options*). Postings still in progress at that point keep running on Hirebase. **Run the actor again with the same job IDs** and it collects them: nothing is queued or charged a second time, and postings already returned in the last 12 hours are skipped unless you turn on *Include previously returned*.

### Pricing

**Pay per contact** - one charge per contact row saved (the price is shown on this page under *Pricing*). A posting typically returns 5-10 contacts. You are not charged for:

- postings that return no contacts, or fail on Hirebase's side (about 1 in 4),
- IDs that aren't a live Hirebase posting,
- postings already returned by another run in the last 12 hours,
- postings still being researched when a run ends - you pay when they're collected.

Your spending limit is respected before research is queued: at about 8 contacts a posting, a run only queues as many new postings as the limit can cover.

### FAQ

**Do I need an API key?**
No - API access is built into the actor.

**Where do I get job IDs?**
From the `id` column of any Hirebase job actor's dataset, or the `samplePostings[].id` field in Company Search. Every posting in the Hirebase index has one.

**Why did a posting return no contacts?**
The research could not find anyone publicly linked to that role at that employer - common for very small companies, agencies posting on behalf of clients, and postings with little public footprint. About 1 in 4 postings end this way, and they are not charged.

**Are the emails verified?**
Emails are included only when Hirebase finds one on a public source; they are not verified, and most rows will not have one. Use the LinkedIn profile, or pass the name and employer to an email-finding tool.

**Is this legal?**
Contacts are business profiles assembled from public professional sources (company pages and public profiles) for a business-contact purpose, with name, job title and profile link only. You are responsible for using the data in line with the laws that apply to your outreach, such as GDPR and CAN-SPAM.

# Actor input Schema

## `jobIds` (type: `array`):

Hirebase job IDs to find contacts for, one per line - the <code>id</code> column of any Hirebase job actor (Job Search, Fresh Jobs Feed, AI Job Search, the ATS scrapers) or the sample postings from Company Search. Each posting is researched separately; about 3 in 4 return contacts.

## `maxJobs` (type: `integer`):

How many of the job IDs to research in this run (up to 100). Hirebase researches roughly a dozen postings an hour, so a full run of 100 can take most of a day - start small.

## `maxWaitMinutes` (type: `integer`):

How long the run keeps waiting for research to finish. Postings still in progress at the limit keep running on Hirebase; run the actor again with the same job IDs to collect them - they are never queued or charged twice. The default fits the standard 1-hour run timeout; for bigger batches raise both this and the run timeout (Run options).

## `retryFailed` (type: `boolean`):

When Hirebase fails a posting with a temporary error, queue it once more. Postings where no contacts could be found are never retried.

## `includePreviouslyReturned` (type: `boolean`):

Save contacts again for postings another run of this actor returned in the last 12 hours (charged again). Off by default, so re-running to collect unfinished postings does not charge you twice for the finished ones. Postings returned longer ago are always included.

## Actor input object example

```json
{
  "jobIds": [
    "6aaab073ab66f31a289662be"
  ],
  "maxJobs": 25,
  "maxWaitMinutes": 55,
  "retryFailed": true,
  "includePreviouslyReturned": false
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset item per likely hiring manager or recruiter, with the posting it was found for.

# 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 = {
    "jobIds": [
        "6aaab073ab66f31a289662be"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hirebase/hiring-manager-contacts").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 = { "jobIds": ["6aaab073ab66f31a289662be"] }

# Run the Actor and wait for it to finish
run = client.actor("hirebase/hiring-manager-contacts").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 '{
  "jobIds": [
    "6aaab073ab66f31a289662be"
  ]
}' |
apify call hirebase/hiring-manager-contacts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hirebase/hiring-manager-contacts"
        }
    }
}
```

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/yLwUasfNDpLRleGGi/builds/jbLaKmr6cxF3Mga4F/openapi.json
