# Hiring Signals Monitor: Buying Signals from Job Postings (`humble-echidna/hiring-signals`) Actor

Turn a list of companies into sales and recruiting signals: new job postings matching your skills or tools (Rust, Kafka, Snowflake), hiring surges, and technologies added to or dropped from their website. Reads Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor. Pay only for signals.

- **URL**: https://apify.com/humble-echidna/hiring-signals.md
- **Developed by:** [Michael Costa](https://apify.com/humble-echidna) (community)
- **Categories:** Lead generation, Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 company signals

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

### What does Hiring Signals Monitor do?

**Hiring Signals Monitor** turns a list of companies into **hiring signals** from their **job postings**: which of
them opened **roles that mention your keywords** (a skill, tool or role: Rust, Kafka, Snowflake, "data engineer"),
which are in a **hiring surge**, and which **added or dropped a technology on their website**. Data comes live from
each company's public job board (Greenhouse, Lever, Ashby, Recruitee, Personio, Teamtailor) and home page.

You get **one row per company that has a signal**, with a one-line summary. Companies with nothing new aren't rows
and **aren't charged**; they're listed in the run summary. It is **not** a job-board search: it checks the companies
you name.

**Try it in one click:** the input comes pre-filled with GitLab, Stripe, Palantir and Linear and the keywords Python,
Kafka and Rust. In a local run on 2026-09-26 that gave 3 companies with a signal (Linear had none), about $0.06
(3 × $0.02, plus $0.00005 for the run start). **Then replace them with your own accounts and keywords.**

| Signal | What it means | Needs |
|---|---|---|
| `new_roles_matching` | Roles that mention a keyword and weren't open at the last run (or, without monitoring, were posted in the last 30 days). | Nothing extra |
| `hiring_surge` | Open roles grew by 20% and at least 5 roles within 30 days (all adjustable). | Monitoring on |
| `stack_added` / `stack_removed` | A technology appeared on, or disappeared from, the company's home page since the last run. | Monitoring on and a website domain |

### Monitor your accounts: signals since the last run, in Slack, email or a webhook

With **Only signals since my last run** on, each run compares every company with the last run of the same search
and returns only what's new: roles that opened since then, a surge, a stack change. A week with nothing new costs
only the run start.

1. Put your companies in **Companies** (add the website after `|`, e.g. `Ramp | ramp.com`, for stack signals),
   your keywords in **Signal keywords**, turn on **Only signals since my last run** (`"sinceLastRun": true`) and
   click **Start**. This first run is the baseline: roles posted in the last 30 days count as new, and the counts and
   tech stacks are recorded for the next runs.
2. Click **Save as a new task**. The memory belongs to that task and its search (keywords, where they're matched,
   departments, locations): changing the keywords starts a new baseline, adding a company doesn't reset the others.
3. In **Schedules**, create a schedule (for example weekly, Monday 06:00) and add the task.
4. On the task's **Integrations** tab, send each run's rows where you work:
   - **Slack**: event "run succeeded", message `{{resource.statusMessage}}` plus a link to
     `https://console.apify.com/storage/datasets/{{resource.defaultDatasetId}}`. Each row's `summary` reads like
     "GitLab: 3 new roles matching Kafka since 2026-09-19 (...); open roles 180 -> 221, +22.8% since 2026-09-01".
   - **Gmail**: attach the dataset as CSV.
   - **HTTP webhook**: `ACTOR.RUN.SUCCEEDED`; fetch
     `GET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json` with your API token.

The pre-filled input with monitoring on, run twice (local runs, 2026-09-26, 10 real companies): the first run gave 5
companies with a signal; the second, minutes later, gave 0 rows and said "0 of 10 companies with a signal, 10 quiet;
compared with the run of 2026-09-27 00:41 UTC".

### What data does Hiring Signals Monitor return?

| Field | Example | Notes |
|---|---|---|
| `company`, `domain` | `GitLab`, `gitlab.com` | `domain` is `null` when none is known (see below). |
| `signalTypes` | `["new_roles_matching", "hiring_surge"]` | One or more of the four signals. |
| `summary` | `GitLab: 22 new roles matching Python, Kafka, Rust posted in the last 30 days (...)` | One line, ready for Slack or a CRM note. |
| `newRoles[]` | `{"title": "Staff Software Engineer - NLP", "url": "...", "location": "Bangalore, India", "postedAt": "...", "matchedKeywords": ["Rust"], "matchedIn": ["description"]}` | Up to 25, title matches first, then newest. `newRoleCount` has the total. |
| `roleCounts` | `{"openNow": 199, "openLastRun": 187, "matchingNow": 44, "changePercent": 6.4, ...}` | Last-run and surge fields are `null` on a baseline. |
| `techStack`, `techStackCheckedAt` | `["Cloudflare", "Marketo", "Nuxt.js", ...]` | The home page's technologies and when they were read (with monitoring, re-read every 7 days by default); `null` if not checked. |
| `stackAdded`, `stackRemoved` | `[{"name": "HubSpot", "categories": ["Marketing automation"]}]` | Empty unless it changed. |
| `baseline`, `previousRunAt` | `false`, `2026-09-19T06:00:03Z` | Whether there was anything to compare with. |

The full list is under [Output](#output).

### How much does it cost to monitor hiring signals?

You pay per company with a signal: **$20.00 per 1,000 company signals** ($0.02 each), plus $0.00005 each time a run
starts. **Companies with nothing new are free**, however many you check; so are companies that fail (board down,
not found) and companies left unchecked by your limits. One row covers everything that company signals in that
run (all its new roles, a surge and stack changes together).

- **The pre-filled example:** 3 companies with a signal × $0.02 = $0.06, plus the start.
- **A month, for example:** 200 target accounts checked weekly with monitoring on. If 15% of them show a signal in a
  given week (an assumption; it depends on your keywords and accounts), that's about 130 rows a month ≈ **$2.60**. A
  week where nothing changes costs $0.00005.
- **Caps:** **Max companies with signals per run** in the input, and **Maximum cost per run** in the run options. The
  run stops cleanly at whichever comes first; the companies it didn't get to are listed in the run summary
  (`notChecked`) and are checked on the next run.

### How to monitor hiring signals

1. Open Hiring Signals Monitor and click **Try for free** (or **Start** if you're signed in).
2. In **Companies**, list your accounts, one per line: a name (`Stripe`), a careers page
   (`https://linear.app/careers`) or a job-board URL (`https://boards.greenhouse.io/gitlab`), optionally followed by
   ` | website.com`.
3. In **Signal keywords**, add the skills, tools or role words that mean "this account is a fit": `Snowflake`,
   `Kafka`, `data engineer`. Optionally limit **Departments** and **Locations**.
4. Turn on **Only signals since my last run** for a scheduled monitor, then click **Start** and open the **Output**
   tab (views: Signals, New matching roles, Website tech stack). Export as JSON, CSV or Excel.

### Example: Python, Kafka and Rust roles at four tech companies

The pre-filled input:

```json
{
  "companies": ["https://boards.greenhouse.io/gitlab | gitlab.com", "https://boards.greenhouse.io/stripe",
                "https://jobs.lever.co/palantir | palantir.com", "Linear | linear.app"],
  "signalKeywords": ["Python", "Kafka", "Rust"]
}
```

Real output from a local run on 2026-09-26: GitLab 22 new matching roles (199 open), Stripe 40 (702 open; its domain
`stripe.com` was found from its job links), Palantir 8 (321 open); Linear had 30 open roles, 1 matching, none posted
in the last 30 days, so it was quiet and not charged. The GitLab row (lists shortened with `...`):

```json
{
  "id": "6aed9a020fa12e6d-20260927T004219",
  "companyId": "6aed9a020fa12e6d",
  "company": "GitLab",
  "input": "https://boards.greenhouse.io/gitlab | gitlab.com",
  "domain": "gitlab.com",
  "domainSource": "input",
  "jobBoards": ["greenhouse:gitlab"],
  "signalTypes": ["new_roles_matching"],
  "summary": "GitLab: 22 new roles matching Python, Kafka, Rust posted in the last 30 days (Staff Software Engineer - NLP; Principal Site Reliability Engineer, Platform Engineering: Dedicated; Staff Backend Engineer, Core DevOps, +19 more)",
  "newRoleCount": 22,
  "newRoles": [
    {"title": "Staff Software Engineer - NLP", "url": "https://job-boards.greenhouse.io/gitlab/jobs/8781299002",
     "location": "Bangalore, India", "department": "Architecture Engineering", "postedAt": "2026-09-24T06:04:48Z",
     "matchedKeywords": ["Rust"], "matchedIn": ["description"]},
    "..."
  ],
  "roleCounts": {"openNow": 199, "openLastRun": null, "matchingNow": 44, "matchingLastRun": null, "newMatching": 22,
                 "surgeReferenceCount": null, "surgeReferenceAt": null, "changePercent": null},
  "techStack": ["Cloudflare", "Cloudinary", "Dreamdata", "GitLab", "HSTS", "HTTP/3", "..."],
  "techStackCheckedAt": "2026-09-27T00:42:19Z",
  "techStackError": null,
  "stackAdded": [],
  "stackRemoved": [],
  "baseline": true,
  "previousRunAt": null,
  "checkedAt": "2026-09-27T00:42:19Z"
}
```

The run summary (`OUTPUT` record) listed the quiet company:
`{"input": "Linear | linear.app", "company": "Linear", "domain": "linear.app", "openRoles": 30, "matchingRoles": 1,
"techCount": 15, "baseline": true}`.

### Input

| Field | What it does |
|---|---|
| **Companies** | One per line: name, careers page or job-board URL (`greenhouse:gitlab` works too), optionally ` \| domain`. Up to 500 per run. |
| **Signal keywords** | Whole words or phrases, case-insensitive. "Go" doesn't match "Google" and "C" doesn't match "C++". Empty: every new role counts. |
| **Match keywords in** | `titleAndDescription` (default) or `title` only. |
| **Departments**, **Locations** | Limit the roles, and the counts used for surges, to these (contains, case-insensitive). |
| **Only signals since my last run** | Monitoring (see above). Off: every run reports matching roles posted in the last **New roles: posted within** days (default 30). |
| **Hiring surge** growth %, minimum roles, window | Default 20%, 5 roles, 30 days. |
| **Check each company's website tech stack** | On by default; one home-page fetch per company per run. |
| **Re-check each home page every (days)** | With monitoring, a home page checked within this many days (default 7) isn't fetched again; `techStackCheckedAt` says when it was read. 1 = every run. |
| **Only these technologies count as stack signals** | e.g. `HubSpot`, `Segment`, `Intercom`. Empty: any change counts. |
| **Max companies with signals per run** | Caps the rows (and so the cost) per run. |

#### Where does the website domain come from?

From what you type after `|`, else from something the company publishes: the careers page you gave
(`https://careers.acme.com` -> `acme.com`), its job links when most of them point to its own site (Stripe's do), or
a Teamtailor career site on its own domain. It's never guessed from the company's name. Without a domain, job
signals work as usual and `techStackError` says how to add one.

### Output

Each row is one company with at least one signal; the fields are the same on every row. Besides the dataset, each
run writes two records to its key-value store:

- `OUTPUT`: the run summary, with `quiet` (companies checked with nothing to report: open and matching roles, domain,
  number of technologies), `failed` (with the reason), `notChecked` (left for the next run by your limits),
  `withSignals` and `limitReached`.
- `RUN_STATS`: per input line, what it resolved to and any problem, plus signal counts by type.

`companyId` is the same for a company on every run, so you can group its signals over time; `id` is unique per row.

### Run it on a schedule, or from your own code

Save your input as a **task**, add it to a **schedule**, and collect rows from
`GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv` with your
API token, a webhook, or Make, Zapier or n8n. A quiet run succeeds with an empty dataset.

#### Can I use Hiring Signals Monitor from an AI agent (MCP)?

Yes. Through Apify's MCP server (`https://mcp.apify.com`) an agent can call it with `companies` and `signalKeywords`
and read back the rows' `summary` lines. Every input field's description states its format, defaults and limits.

### Who it's for

- **Sales and business development**: buying signals on a list of target accounts, the moment one starts hiring for
  the thing you sell into (a data team hiring Snowflake engineers, a company adding a marketing-automation tool),
  weekly.
- **Recruiters and agencies**: which client or target companies just opened roles in your specialty.
- **Investors and analysts**: hiring surges and stack changes across a watchlist.

### Why this one?

- **Signals, not raw job dumps.** One row per company that changed, with a summary, instead of thousands of job
  rows to diff yourself. Quiet companies are free.
- **Three signal kinds in one run**: matching new roles, hiring surges and website tech-stack changes (the detector
  behind [Website Technology Detector](https://apify.com/humble-echidna/tech-stack-detector): 100% precision, 98%
  recall on a 181-site hand-checked benchmark, 2026-09-25).
- **Guards against false signals**: a failed board isn't evaluated, a role that briefly disappears isn't re-announced,
  a board that suddenly lists nothing is held for a run, and a home page that fails or goes blank never reports
  technologies removed.
- **Live, not a cached index**: every run reads the boards and pages at that moment.
- **Polite and safe.** It identifies itself honestly (User-Agent `HumbleEchidnaApify`), follows each site's
  robots.txt and Crawl-delay, and only requests public web addresses on the standard ports (80 and 443).
- **Reliable.** One failing company never affects the others; the log, `OUTPUT` and `RUN_STATS` say which and why.

### Limits

- Only companies whose jobs are on **Greenhouse, Lever, Ashby, Recruitee, Personio or Teamtailor**. Workday, iCIMS,
  SmartRecruiters, Workable and others are refused with the reason (their terms or robots.txt don't allow this use).
  Careers pages that load jobs with JavaScript or block bots can't be scanned; paste the job-board URL instead.
- Surges and stack changes need monitoring on (a previous run to compare with).
- The tech stack comes from one page, the home page, fetched without a browser: technologies that only load through
  JavaScript can be missed, and a site behind a bot check is reported as not checked.
- Up to 500 companies per run; split longer lists into several tasks.
- Keyword matching is literal: a keyword in a description ("nice to have: Kafka") counts. Use **Match keywords in:
  title** for stronger, fewer matches.

### FAQ

#### Is it legal to monitor hiring signals from job boards?

It reads only feeds each platform publishes for machines, for the companies you list, and each platform's terms
were checked before it was added. Greenhouse's docs say "Job Board data is publicly available"; Lever's postings API
says published postings "may be scraped by third parties"; Ashby, Recruitee, Personio and Teamtailor document their
public job feeds, and their terms bind their customers, not feed readers (details and links in the Changelog). The
home page is fetched once, as a normal logged-out visitor, following robots.txt. It collects job postings and
technology names only: no recruiter names, emails or other personal data.

#### Why is a company missing from the results?

It had no signal (it's in `OUTPUT.quiet`, with its open and matching role counts), it failed (`OUTPUT.failed`, with
the reason: board not found, not a supported platform, blocked by robots.txt), or your limits stopped the run first
(`OUTPUT.notChecked`).

#### Does it support Workday, iCIMS or LinkedIn?

No. Their terms or robots.txt don't allow this use, so they're refused with the reason instead of scraped.

#### How is this different from a job scraper?

A job scraper returns every job and leaves the comparison to you. This returns only companies where something
changed, with the change summarised, and doesn't charge for the rest. If you want every job, use
[Company Career Page Jobs Scraper](https://apify.com/humble-echidna/ats-jobs).

#### How fresh is the data?

Live: each run reads the job boards and home pages at that moment.

### Related actors

| Actor | Use it when |
|---|---|
| [Company Career Page Jobs Scraper](https://apify.com/humble-echidna/ats-jobs) | You want every job at these companies, or new, changed and closed jobs, as rows. |
| [Website Technology Detector](https://apify.com/humble-echidna/tech-stack-detector) | You want full tech-stack detail (versions, evidence, categories) for a list of websites. |

### Feedback and support

Found a bug, or need a platform or signal that isn't here? Open an issue on the **Issues** tab with the input you
used.

### Versions

Current version: **1.0**. See the Changelog tab for what changed in each version.

# Changelog

This Actor's version history is a separate document: https://apify.com/humble-echidna/hiring-signals/changelog.md

# Actor input Schema

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

One company per line: a company name (e.g. Stripe), its careers page (e.g. https://linear.app/careers) or its job-board URL (e.g. https://boards.greenhouse.io/gitlab, or greenhouse:gitlab). Boards on Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor are read. Add the website after `|` for tech-stack checks, e.g. `Ramp | ramp.com`; without it the domain is taken only from the careers page or job links. Up to 500 companies per run.

## `signalKeywords` (type: `array`):

Roles count as a signal when they mention any of these as a whole word or phrase, case-insensitive: e.g. `Rust`, `Kafka`, `Snowflake`, `data engineer`. "Go" doesn't match "Google", but a short word can still match unrelated text, so prefer specific terms. Leave empty to count every new role (inside the department and location filters). Default: Python, Kafka, Rust.

## `matchIn` (type: `string`):

Where the signal keywords are looked for: `titleAndDescription` (default; skills are mostly named in the description) or `title` (fewer, stronger matches, e.g. "Senior Rust Engineer").

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

Only roles whose department or team contains any of these words (case-insensitive), e.g. `Engineering`, `Data`. Also limits the open-role counts used for hiring surges. Leave empty for every department.

## `locations` (type: `array`):

Only roles whose location or country contains any of these (case-insensitive), e.g. `London`, `Germany`, `Remote`. Also limits the open-role counts used for hiring surges. Leave empty for everywhere.

## `sinceLastRun` (type: `boolean`):

On: each run compares every company with the last run of the same search (saved task) and returns only what's new since then: new matching roles, hiring surges and website stack changes. The first run is the baseline (roles posted in the last `lookbackDays` count as new). Off (default): every run reports matching roles posted in the last `lookbackDays` days; surges and stack changes need this on.

## `lookbackDays` (type: `integer`):

With monitoring off, and on the first monitoring run, a matching role counts as new when its job board says it was posted within this many days. 1 to 365, default 30. Roles without a posting date don't count as new.

## `surgePercent` (type: `integer`):

A hiring surge is reported when a company's open roles (inside the department and location filters) grew by at least this percentage within the surge window, and by at least the minimum number of roles. 1 to 1000, default 20. Needs monitoring on.

## `surgeMinRoles` (type: `integer`):

The least number of extra open roles that makes a surge, so a board going from 2 to 3 roles isn't one. 1 to 10000, default 5.

## `surgeWindowDays` (type: `integer`):

Growth is measured from the oldest run inside this many days (or the latest run before it). The same surge isn't reported again within the window unless the roles grow by the same margin again. 1 to 90, default 30.

## `detectTechStack` (type: `boolean`):

On (default): the company's home page is fetched once per run and its technologies (CMS, analytics, frameworks, CDN...) are listed; with monitoring on, technologies added or dropped since the last run are signals. Needs a domain (see `companies`). Off: job signals only.

## `stackCheckEveryDays` (type: `integer`):

With monitoring on, a home page checked less than this many days ago isn't fetched again; its last stack is reported (`techStackCheckedAt` says when) and stack changes show up at the next check. Stacks change slowly, so this keeps daily monitors cheap. 1 to 90, default 7; 1 checks every run.

## `stackTechnologies` (type: `array`):

Optional. When set, only these technologies being added or dropped count as a stack signal, e.g. `HubSpot`, `Segment`, `Intercom` (names as shown in `techStack`, case-insensitive). Empty (default): any technology change counts.

## `maxResults` (type: `integer`):

Stop after this many companies with a signal (one result each), e.g. 50. Minimum 1; leave empty (the default) for no limit. Quiet companies are never results and don't count. The run also stops cleanly at the maximum cost per run you set in the run options, whichever comes first.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/gitlab | gitlab.com",
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir | palantir.com",
    "Linear | linear.app"
  ],
  "signalKeywords": [
    "Python",
    "Kafka",
    "Rust"
  ],
  "matchIn": "titleAndDescription",
  "sinceLastRun": false,
  "lookbackDays": 30,
  "surgePercent": 20,
  "surgeMinRoles": 5,
  "surgeWindowDays": 30,
  "detectTechStack": true,
  "stackCheckEveryDays": 7
}
```

# Actor output Schema

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

No description

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

No description

## `runStats` (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 = {
    "companies": [
        "https://boards.greenhouse.io/gitlab | gitlab.com",
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir | palantir.com",
        "Linear | linear.app"
    ],
    "signalKeywords": [
        "Python",
        "Kafka",
        "Rust"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("humble-echidna/hiring-signals").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": [
        "https://boards.greenhouse.io/gitlab | gitlab.com",
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir | palantir.com",
        "Linear | linear.app",
    ],
    "signalKeywords": [
        "Python",
        "Kafka",
        "Rust",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("humble-echidna/hiring-signals").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": [
    "https://boards.greenhouse.io/gitlab | gitlab.com",
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir | palantir.com",
    "Linear | linear.app"
  ],
  "signalKeywords": [
    "Python",
    "Kafka",
    "Rust"
  ]
}' |
apify call humble-echidna/hiring-signals --silent --output-dataset

```

## MCP server setup

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

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/6r1gX9dE3mlLFu385/builds/CghsWOVLfSdYrM1Qn/openapi.json
