# ICP-Qualified Hiring Reqs (`reqbeat/icp-qualified-hiring-reqs`) Actor

Get the hiring reqs that match your ICP definition — company market and size, seniority, skills, geography — from an already-normalized cross-source corpus, with agency and aggregator postings excluded.

- **URL**: https://apify.com/reqbeat/icp-qualified-hiring-reqs.md
- **Developed by:** [Reqbeat](https://apify.com/reqbeat) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$250.00 / 1,000 qualified reqs

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

## ICP-Qualified Hiring Reqs — deduped, agency-filtered, salary-banded

Stop pulling five thousand unfiltered job postings and filtering them yourself. Get only
the reqs that match your ICP — company size, market, geography, skills, seniority — with
agency and aggregator postings already removed, duplicates already collapsed, and an
estimated salary band on every one.

### Not a job scraper

This actor does not scrape at run time. It serves an already-normalized, cross-source,
deduplicated corpus, so it filters on attributes a scraper never has: extracted skills,
normalized seniority and job family, an inferred salary band with its sample count,
work-authorization and regional eligibility scope, ATS provider and apply-link precision,
and company kind — which is how it excludes staffing-agency and aggregator postings, i.e.
your competitors' listings, from the result. Each result is an ICP match rather than a
keyword hit, and names the board it was detected on and its own address, so the origin of
anything you are served is inspectable rather than asserted.

### Your ICP, as input

Every input is optional and they combine with AND, so a result satisfies all of them at
once. Leave one empty and it constrains nothing.

**The company** — industry (exact label or substring), country, size band
(1-10 … 5001+), kind, or a list of specific Reqbeat company ids.

**The req** — seniority, job family, skills, remote type, country, location keywords and
title keywords matched as whole words (so "go" reaches *Go Engineer* and never *Django
Developer*, and "london" reaches *London Area* and never *Londonderry*), and title
exclusions that veto a match.

**The source** — board, source type, or ATS vendor.

**The pay band** — a yearly-USD floor, a ceiling, or both. The figure compared is the
employer's declared salary where there is one and our inferred median otherwise, and the
inferred one qualifies only above a sample floor.

**The run** — agency exclusion and the liveness filter are both on by default, resuming
from your last run is on by default so a scheduled run returns only what has arrived
since, and a ceiling caps what one run delivers.

### What comes back

One dataset entry per qualified req, passed through exactly as the corpus serves it —
company facts, the normalized req, declared and inferred compensation with its sample
count, eligibility scope, provenance, apply precision, and a stable req key you can fold
or join on. The dataset's **Provenance** view shows the origin fields on their own.

### Latency

Detection latency, not real time. Across the corpus we detect a req a median of 9 hours
after it is published, and 48 hours at the 95th percentile, measured on 2026-08-08 over a
14-day ingest window. The spread by source is wide — 12 min for Lever, 3.07 days for
Workday — so no single bound holds across vendors. Each of these is a floor rather than a
point estimate: 7.94% of corpus records carry a publication timestamp stamped at ingest,
which reads as zero delay. This actor competes on qualification, not on speed.

### Liveness

Some of what we return has already been taken down. A stratified re-fetch of 500 sampled
posting URLs on 2026-09-02 found 16.7% of them, weighted back to corpus volume, dead or
expired (95% CI 12.3-21.2%) across a 14-day frame. The two strata differ, and not in the
direction a buyer expects: 18.1% of postings read directly from an employer's
applicant-tracking system against 5.8% of postings read from aggregators. We publish the
rate rather than a per-posting liveness claim, because the second one needs a re-fetch we
do not run per result.

live\_only defaults to true. Every req carries a lifecycle status, and postings whose status
is no longer current are dropped before you are charged for them. The filter is
deliberately narrower than its name: a req whose status the corpus has not re-read since it
was detected is kept rather than dropped, because an unread status is not evidence of a
dead posting. So the rate above is published as well as filtered on — the filter removes
what is known dead, not everything that has died.

### Sources and apply links

Where the postings come from. 6.29% of live non-synthetic reqs in the corpus name an
applicant-tracking system as their source; the other 93.7% carry a job-board or aggregator
URL. Every req we return names its own source, and this actor makes no promise about how
many of them carry an employer-side application URL.

apply\_precision on every result. Every req carries its application URL, the kind of
destination that URL is, and the precision of the match, so you can tell an employer-side
destination from an aggregator redirect before you spend a click. Each result also states
whether following it leaves the site the posting was detected on.

### Provenance

Per-source provenance on every result. Every req names the board it was detected on and
carries its own address, so a buyer can attribute any result to its source rather than
taking the corpus on trust. Every req also states the kind of source it came from — an
employer's own applicant-tracking system, or a job board — which is the same fact the
corpus-admission rule is applied on, so the rule is verifiable rather than asserted. Where
the source is an applicant-tracking system the req names which one, where the source stated
a publication date the req carries it, and every req states when the corpus last read it,
left empty where no read time was recorded rather than filled in from another timestamp.
Provenance is per req and never per run: a run-level summary would establish that a source
is present without saying which results came from it, which is the worst of both.

### Pricing

Free allowance, and what happens when it runs out. The first 10 qualified reqs each
calendar month are free. Starting a run costs nothing and a run that matches nothing costs
nothing — you are charged per qualified req, after it has been delivered, never for
starting. When nothing further can be charged — the free allowance is spent and the
maximum cost you set for the run leaves no room — the run returns
{quota\_exceeded: true, matched: N, returned: M, upgrade\_url} and stops there, so an
exhausted allowance reads as an answer rather than as a shortened result or a platform
fault. That matched figure counts what the run saw and is a floor: reading the rest of
your ICP to report an exact total would spend your own quota on qualified reqs you were
never given. Your next run resumes at the first qualified req this one did not deliver.

### When nothing matches

A run that matches nothing tells you why, and costs nothing. Qualification answers only
what your ICP matches on every constraint at once, so an ICP that is narrow in one place
returns nothing at all. Instead of an empty result, that run returns one free diagnostic
naming the constraint that zeroed the match and the loosened ICP that would have matched
— each one tested against the corpus during your own run, not read off a table. Nothing
is charged for it.

### When a value cannot be resolved

An ICP value we cannot resolve is refused, not silently ignored. Where a field has a
closed vocabulary — country is the one buyers meet first — a value outside it cannot
match anything we hold. Rather than answer a narrower question than you asked, or none at
all, that run returns one free item carrying our own reply: the value that did not
resolve, and what to type instead. Nothing is charged for it, and your next run picks up
where the corrected ICP starts.

### When a value will not be sent

An ICP we will not send is refused before the run costs you anything. Some values we can
rule out without asking the corpus at all — a company size outside the ladder we hold, a
pay band whose floor sits above its ceiling, a run started with no ICP in it — and those
are answered here rather than sent on. That run returns one free item naming the value we
would not take and what to set instead, on a run that finished successfully. Nothing is
charged for it, and nothing is delivered.

### The corpus

What the corpus is, and what it is not. Every value this actor serves about a company or a
posting is read from a public job advertisement — on the employer's own applicant-tracking
system, on a public job board, or on an aggregator that re-lists them. None of it is
bought from a private database or a people-data broker. LinkedIn's public job listings are
one of those public sources and a substantial part of the corpus is read from them; what
is read there is the advertisement itself, exactly as on any other board. The complete
list of fields Reqbeat holds and serves is published at reqbeat.com/data-ethics. No
contact PII of any kind — no name, email address, phone number or profile of a natural
person — is ever served as a field.

### Using what you are served

What this actor delivers is a qualified, derived cut: your ICP definition applied to a
normalized corpus, with agency and aggregator postings excluded and duplicates collapsed.
Use it inside your own pipelines, products and outreach. It is not licensed for resale or
redistribution as a standalone job-posting dataset — the same boundary
[reqbeat.com/terms](https://reqbeat.com/terms) draws for the API this actor calls.

### Reqbeat

The same corpus is available directly as an API, with saved-search delivery and an MCP
server: [reqbeat.com](https://reqbeat.com) ·
[pricing](https://reqbeat.com/pricing) ·
[data ethics](https://reqbeat.com/data-ethics) ·
[terms](https://reqbeat.com/terms)

# Actor input Schema

## `industry` (type: `array`):

Match the company's industry label exactly. Supply several to match any of them.

## `industry_terms` (type: `array`):

Match the company's industry label by substring, so "internet" reaches "Technology, Information and Internet". Use this when the exact label is longer than the market you mean.

## `company_kind` (type: `array`):

Restrict to companies of a given kind. Most buyers leave this empty and use "Exclude agencies and aggregators" below instead.

## `company_country` (type: `array`):

The country the company itself is in, as distinct from where a given req is located.

## `headcount_band` (type: `array`):

Pick one or more employee-count bands. Size is a band rather than a numeric range, so a company is in exactly one of these and "50-100" is not a size this corpus can be asked about.

## `seniority_level` (type: `array`):

The normalized seniority of the req, extracted from the posting rather than read off its title.

## `job_family` (type: `array`):

The normalized job family of the req. This is the axis to use for broad functional targeting.

## `remote_type` (type: `array`):

The working arrangement the posting states.

## `skills` (type: `array`):

Match a req carrying any of these extracted skills.

## `title_keywords` (type: `array`):

Match whole words in the posting title, so "go" matches "Go Engineer" and never "Django Developer". Supply several to match any of them.

## `title_excludes` (type: `array`):

Veto a req whose title carries any of these whole words — "sales" and "recruiter" against a keyword of "engineer", for instance. A req whose title we do not hold is not vetoed: an unknown title cannot prove an exclusion.

## `location_keywords` (type: `array`):

Match whole words in the req's stated location, so "london" reaches "London Area" and "Greater London" but never "Londonderry". This narrows within a country rather than replacing "Req country". A city spelled differently is a different word — supply "munich" and "münchen", or "cologne" and "köln", as separate keywords to match either.

## `board` (type: `array`):

Restrict to reqs detected on a given board.

## `source_type` (type: `array`):

Restrict to a class of source rather than a named one.

## `ats_vendor` (type: `array`):

Restrict to reqs whose source is a given applicant-tracking system.

## `country` (type: `array`):

The country the req itself is located in.

## `company_ids` (type: `array`):

Restrict to named accounts by their Reqbeat company id.

## `exclude_agencies` (type: `boolean`):

Drop staffing-agency, aggregator and job-board postings, so a result names the employer rather than someone re-listing them. On by default.

## `live_only` (type: `boolean`):

Drop reqs whose recorded lifecycle status is no longer current. This reads the status the corpus holds; it is not a re-fetch of the posting at run time. On by default.

## `salary_min_usd` (type: `integer`):

Keep reqs at or above this yearly USD figure. The figure compared is the employer's declared salary where there is one and our inferred median otherwise, and the inferred one qualifies only above a sample floor. A req carrying no pay information at all matches no band.

## `salary_max_usd` (type: `integer`):

Keep reqs at or below this yearly USD figure. Either bound alone is half-open; both together bracket one comparable figure per req.

## `since` (type: `string`):

An ISO-8601 timestamp. Only reqs first seen after it are returned.

## `since_last_run` (type: `boolean`):

Resume from where your previous run of this actor finished, so a scheduled run returns only what has arrived since. Kept per account in this actor's own key-value store. On by default; turn it off to re-read the whole ICP from the start.

## `max_reqs` (type: `integer`):

A ceiling on what one run delivers. Leave empty to take everything matching your ICP. The first 10 qualified reqs each calendar month are free. Starting a run costs nothing and a run that matches nothing costs nothing — you are charged per qualified req, after it has been delivered.

## `page_size` (type: `integer`):

How many reqs to ask for at a time, between 1 and 100. Affects pacing only, never the total.

## Actor input object example

```json
{
  "exclude_agencies": true,
  "live_only": true,
  "since_last_run": true,
  "page_size": 25
}
```

# Actor output Schema

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

No description

## `provenance` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("reqbeat/icp-qualified-hiring-reqs").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("reqbeat/icp-qualified-hiring-reqs").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 '{}' |
apify call reqbeat/icp-qualified-hiring-reqs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reqbeat/icp-qualified-hiring-reqs"
        }
    }
}
```

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/VvWtPZSqckfcgEhrw/builds/9A1QJ1Qa4x995cpoL/openapi.json
