# Company Hiring Signals (Greenhouse, Lever, Ashby + More) (`fluted_mirror/ats-hiring-signals`) Actor

Turn company names or careers URLs into hiring signals: open roles by department and location, remote share, posts in the last 30 days, and roles added/removed since your last run. Uses companies' own public job-board APIs.

- **URL**: https://apify.com/fluted_mirror/ats-hiring-signals.md
- **Developed by:** [Troy Daniels](https://apify.com/fluted_mirror) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 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

## Company Hiring Signals (Greenhouse, Lever, Ashby + More)

Give it a company name or careers URL, and get back **one clean row per company** saying what it's hiring for right now:

- Total open roles, and how many were posted in the last 30 days
- Top departments and locations
- Remote share, and how many roles list a salary
- **New and removed roles since your last run** when persistent monitoring state is available (see Monitoring below), so you can schedule it daily or weekly and see when a company starts hiring sales, security or AI people

You can also turn on **every job row**: title, department, location, remote flag, type, date posted, link and salary where it's published. All ATSs come back in the same format.

### Why it's reliable

It reads each company's **own public job-board API** (Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee). Those are official, keyless JSON endpoints, the same ones that power the company's careers page. It doesn't scrape LinkedIn or Indeed, so there's no login, no browser and no anti-bot blocking. That makes runs fast and cheap.

### Use cases

- **B2B sales signals:** "Acme just opened 6 security roles" is a trigger to reach out
- **Investors and analysts:** track hiring velocity across a portfolio or watchlist
- **Recruiters and job boards:** pull normalised jobs from hundreds of companies in one run
- **AI agents** through the Apify MCP server: "Which of these 40 companies posted ML roles this month?"

### Input

```json
{ "companies": ["stripe", "https://jobs.ashbyhq.com/ramp", "lever:palantir"],
  "includeJobs": false, "monitorChanges": true, "maxJobsPerCompany": 2000 }
```

Bare names are auto-detected, trying Greenhouse, then Lever, Ashby, SmartRecruiters and Recruitee. For an exact match, use a careers URL or `ats:slug`.

### Output: company row

```json
{ "type": "company", "company_slug": "stripe", "ats": "greenhouse", "open_roles": 731,
  "posted_last_30_days": 273, "remote_share": 0.157, "with_salary": 0,
  "top_departments": {"Engineering": 210}, "top_locations": {"San Francisco, CA": 120},
  "new_since_last_run": ["greenhouse:stripe:123"], "removed_since_last_run": [] }
```

### Monitoring (new / removed roles)

With `monitorChanges` on (the default), the Actor records the job IDs it saw under `PREVIOUS_JOB_IDS`.
By default that record lives in the run's own key-value store, so it does **not** persist across runs and no new/removed diff is reported.
To track changes across runs, create a key-value store in your own Apify account and pass its ID as the optional `keyValueStoreId` input; that store is then used for the record.
If a store cannot be opened (for example, Apify store runs run under limited permissions, which block named stores), the Actor logs a warning and still returns the company results without change tracking -- monitoring never fails the run.

### Pricing (pay per event)

- `company-analyzed`: **$0.01 per company found**. Companies that aren't found are free.
- `job-returned`: **$0.001 per job row** ($1 per 1,000), only when "Also return every job row" is on

### Limitations

- Workday, Teamtailor, Workable and custom career sites aren't supported yet.
- `remote_share` uses each ATS's own remote flag. Ashby marks a role remote whenever any of its locations is remote.
- Only public job postings are read. No applicant or personal data is involved.

# Actor input Schema

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

Company slug (stripe), careers URL (https://jobs.lever.co/palantir) or ats:slug (ashby:ramp). Bare names are auto-detected across supported ATSs.

## `includeJobs` (type: `boolean`):

Off = one summary row per company. On = also one normalised row per open job (charged per job).

## `monitorChanges` (type: `boolean`):

Reports new/removed roles when previous state is available. By default state is kept only in the run's own store, so it does not persist across runs; supply keyValueStoreId for persistent tracking. If the store is not accessible (e.g. limited-permission store runs), the run continues without change tracking instead of failing.

## `maxJobsPerCompany` (type: `integer`):

Cap on jobs read per company.

## `keyValueStoreId` (type: `string`):

Optional ID of a key-value store you own, used to persist PREVIOUS_JOB_IDS between runs so new/removed roles can be reported. Leave empty to use the run's own store (no cross-run persistence). If the store cannot be opened, the run still returns results without change tracking.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "https://jobs.ashbyhq.com/ramp",
    "lever:palantir"
  ],
  "includeJobs": false,
  "monitorChanges": true,
  "maxJobsPerCompany": 2000,
  "keyValueStoreId": ""
}
```

# Actor output Schema

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

Every row in the default dataset: company summaries, job rows (if requested) and error rows.

## `companySummaries` (type: `string`):

The companies view: one row per company with open_roles, posted_last_30_days, remote_share, top departments/locations and new/removed roles since the last run.

## `jobRows` (type: `string`):

The jobs view: one normalised row per open job. Only present when includeJobs is true.

# 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": [
        "stripe",
        "https://jobs.ashbyhq.com/ramp",
        "lever:palantir"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fluted_mirror/ats-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": [
        "stripe",
        "https://jobs.ashbyhq.com/ramp",
        "lever:palantir",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fluted_mirror/ats-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": [
    "stripe",
    "https://jobs.ashbyhq.com/ramp",
    "lever:palantir"
  ]
}' |
apify call fluted_mirror/ats-hiring-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fluted_mirror/ats-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/ouZUN3v69jJSHx0YP/builds/ZWZe1FX61HwKO5aqS/openapi.json
