# Company Hiring Signals API - New Jobs, Closed Jobs, History (`martin10291/company-hiring-signals-history`) Actor

Company hiring signals from our own daily archive of public job boards (Greenhouse, Lever and Ashby) for 813 tech and startup companies. Per company and day: open jobs, new postings, closed postings (missing two days in a row) with days open, departments and remote share. Ask which companies are hir

- **URL**: https://apify.com/martin10291/company-hiring-signals-history.md
- **Developed by:** [Martin Petrov](https://apify.com/martin10291) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 API - New Jobs, Closed Jobs, History

**Which companies are hiring fast right now, which teams are they growing, and which roles just closed?** Job boards only show today. This actor answers from our own **daily archive** of public job boards (Greenhouse, Lever and Ashby) for **813 tech and startup companies** and returns clean JSON rows.

No login, no proxies, no scraping on your run: the actor reads our archive, so results come back in seconds. Company data only, no recruiter names or other personal data.

### Use cases

- **B2B sales intent signals.** A company that adds 40 sales roles or 20 engineers is growing and buying tools. Rank companies by new jobs and reach out while the budget is fresh.
- **Recruiters and agencies.** See which companies open many roles in a department, and which roles closed (filled or pulled) and after how many days.
- **Investors and analysts.** Track startup growth through open-job counts per day, hiring velocity and remote share.
- **Job seekers.** Alert feed: new jobs matching your keywords, location or remote preference at the companies you care about.

### What makes this one different

- **Daily history, not a live snapshot.** Scrapers show job boards as they are right now. Our archive stores open jobs per company per day since **2026-11-03** and grows every day. A clone cannot backfill the days it did not record.
- **New and closed detection.** New = first seen after the baseline. Closed = missing from the board 2 days in a row, with **days open** for each closed posting.
- **Hiring velocity per company**: change in open jobs, percent change, new and closed jobs, top departments and remote share.
- **One call for 813 companies** instead of crawling hundreds of job boards yourself.

**Honest limits:** coverage is 813 companies on Greenhouse, Lever and Ashby (mostly tech and startups, many in the US), not the whole market. Closed postings and days open become meaningful after a few days of history, so `closed_jobs` can be empty in the first days (the run still succeeds). For any company that is not in the archive use the live [ATS Jobs Aggregator](https://apify.com/martin10291/ats-jobs-aggregator).

### Modes

| Mode | What you get |
|---|---|
| `top_hiring` (default) | Companies ranked by new jobs, open jobs, change in open jobs or closed jobs over `lookbackDays` |
| `companies` | Current numbers plus the daily history (open, new, closed jobs) of the companies you list |
| `new_jobs` | Job feed of postings first seen after the baseline, with filters |
| `closed_jobs` | Postings that disappeared, with `daysOpen` |
| `open_jobs` | Currently open postings, with filters |

### How to use it (step by step)

1. Click **Try for free**.
2. Keep the default (top 50 companies by new jobs) or choose a mode.
3. Click **Start** and download JSON, CSV or Excel, or call it by API.

### API example (copy and paste)

Replace `MY_APIFY_TOKEN` with your token from Apify Console, Settings, Integrations.

```bash
curl -s -X POST "https://api.apify.com/v2/acts/martin10291~company-hiring-signals-history/run-sync-get-dataset-items?token=MY_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"top_hiring","sortBy":"newJobs","limit":20}'
```

New engineering and sales jobs at target companies:

```bash
curl -s -X POST "https://api.apify.com/v2/acts/martin10291~company-hiring-signals-history/run-sync-get-dataset-items?token=MY_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"new_jobs","companies":["stripe","writer"],"keywords":["engineer","sales"],"limit":50}'
```

### Use it from AI agents (MCP)

Add the actor to Claude, Cursor or any MCP-capable agent with the Apify MCP server:

```
https://mcp.apify.com?tools=martin10291/company-hiring-signals-history
```

Then ask: "Which companies added the most sales roles this month?" The output is flat, documented JSON.

### Alerts: new jobs at my target companies

Set `onlyNew` to true and a `monitorId`. In the job modes (`new_jobs`, `closed_jobs`, `open_jobs`) you get each posting once. In `top_hiring` and `companies` modes you get only rows whose open, new or closed job counts changed since the last run with the same Monitor ID (`change` is `new` or `changed`). The first run reports everything. Schedule it daily and connect a webhook, Slack or email. Each result is paid for once.

### Input

| Field | Default | Description |
|---|---|---|
| `mode` | top_hiring | top_hiring, companies, new_jobs, closed_jobs or open_jobs |
| `sortBy` | newJobs | Ranking for top_hiring: newJobs, openJobs, openJobsDelta, closedJobs |
| `minOpenJobs` | 5 | Skip tiny boards (top_hiring) |
| `lookbackDays` | 30 | Compare with this many days ago (top_hiring) |
| `companies` | empty | Board slugs or names (required for companies mode, filter in job modes) |
| `keywords` | empty | Job title contains any of these (job modes) |
| `location` | empty | Location contains any of these (job modes) |
| `department` | empty | Departments to keep (job modes) |
| `remoteOnly` | false | Only remote postings (job modes) |
| `ats` | empty | greenhouse, lever, ashby |
| `since` | empty | YYYY-MM-DD (job modes) |
| `limit` | 50 | Max rows (1-1000) |
| `onlyNew` | false | Only new or changed rows since last run |
| `monitorId` | default | Separate memory per watch list |

### Output example (top_hiring mode, real data from 2026-11-04)

```json
{
  "company": "Writer",
  "companySlug": "writer",
  "ats": "ashby",
  "openJobs": 91,
  "openJobsThen": 46,
  "openJobsDelta": 45,
  "openJobsDeltaPct": 97.8,
  "newJobs": 45,
  "closedJobs": 0,
  "remoteSharePct": 100.0,
  "topDepartments": [
    {"department": "Engineering, product & design", "openJobs": 36},
    {"department": "Delivery & customer success", "openJobs": 28},
    {"department": "Sales", "openJobs": 15}
  ],
  "lastChecked": "2026-11-04",
  "comparedWith": "2026-11-03",
  "day": "2026-11-04",
  "archiveFrom": "2026-11-03",
  "archiveSnapshots": 2
}
```

Job modes return one posting per row, for example from `new_jobs`:

```json
{
  "company": "Censys",
  "companySlug": "censys",
  "ats": "greenhouse",
  "jobId": "8846269002",
  "title": "Software Engineer II (Backend)",
  "department": null,
  "location": "Remote (US/Canada)",
  "remote": true,
  "url": "https://job-boards.greenhouse.io/censys/jobs/8846269002",
  "firstSeen": "2026-11-04",
  "lastSeen": "2026-11-04",
  "closedAt": null
}
```

`closed_jobs` rows also contain `daysOpen` and `daysOpenNote`. Fields the job board does not provide (for example `department`) are `null`.

### Pricing

Pay per result, **$2 per 1,000 results**. The Run summary record (`RUN_SUMMARY`) reports counts, the archive range and `lastError`.

### FAQ

**Where does the data come from?** From our own daily snapshots of public company job boards on Greenhouse, Lever and Ashby, not from your run.

**Which companies are covered?** 813 tech and startup companies, many in the US. Use the [ATS Jobs Aggregator](https://apify.com/martin10291/ats-jobs-aggregator) for any other company.

**How far back does history go?** To 2026-11-03. Each day adds one snapshot, so lookbacks get more meaningful over time.

**Why is `closed_jobs` empty?** A posting counts as closed after it is missing 2 days in a row, so this is normal in the first days. The run still succeeds and RUN_SUMMARY explains it.

**Is personal data included?** No. Only company and job posting data, no recruiter or candidate names.

# Actor input Schema

## `mode` (type: `string`):

top_hiring = companies ranked by hiring activity; companies = current numbers plus daily history for chosen companies; new_jobs = postings first seen after the archive baseline; closed_jobs = postings that disappeared (with days open); open_jobs = currently open postings.

## `sortBy` (type: `string`):

Ranking for top_hiring mode: new postings, open postings, change in open postings, or closed postings over the lookback window.

## `minOpenJobs` (type: `integer`):

Skip companies with fewer open jobs than this (top_hiring mode). Hides tiny boards.

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

Compare today with this many days ago (top_hiring mode). The archive starts on 2026-11-03, so the maximum useful value is the number of days since then.

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

Company board slugs (for example stripe) or company names. Required in companies mode; optional filter in the job modes.

## `keywords` (type: `array`):

Job modes only: keep postings whose title contains any of these words (case-insensitive). Empty = all titles.

## `location` (type: `array`):

Job modes only: keep postings whose location contains any of these texts, for example Berlin or United States. Empty = all locations.

## `department` (type: `array`):

Job modes only: keep postings in these departments, for example Sales or Engineering. Empty = all departments.

## `remoteOnly` (type: `boolean`):

Job modes only: keep only postings marked as remote.

## `ats` (type: `array`):

Limit to companies using these systems. Empty = all three.

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

Job modes only: postings first seen (or closed) since this date, format YYYY-MM-DD. Empty = since the start of the archive.

## `limit` (type: `integer`):

Maximum number of rows to return (1 to 1000). You pay per result.

## `onlyNew` (type: `boolean`):

For alerts: in the job modes output only postings not reported before; in top_hiring and companies modes output only rows whose open, new or closed job counts changed since the last run with the same Monitor ID. The first run reports everything. Each result is paid for once.

## `monitorId` (type: `string`):

Separate memory for each watch list (used with only-new mode). Use a different ID per list of companies or keywords.

## Actor input object example

```json
{
  "mode": "top_hiring",
  "sortBy": "newJobs",
  "minOpenJobs": 5,
  "lookbackDays": 30,
  "companies": [
    "stripe",
    "writer"
  ],
  "keywords": [
    "engineer",
    "sales"
  ],
  "location": [],
  "department": [],
  "remoteOnly": false,
  "ats": [],
  "since": "",
  "limit": 50,
  "onlyNew": false,
  "monitorId": "default"
}
```

# Actor output Schema

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

One row per company (open, new and closed jobs, departments, remote share, history) or per job posting (title, department, location, remote, url, first seen, closed date, days open).

# 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",
        "writer"
    ],
    "keywords": [
        "engineer",
        "sales"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("martin10291/company-hiring-signals-history").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",
        "writer",
    ],
    "keywords": [
        "engineer",
        "sales",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("martin10291/company-hiring-signals-history").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",
    "writer"
  ],
  "keywords": [
    "engineer",
    "sales"
  ]
}' |
apify call martin10291/company-hiring-signals-history --silent --output-dataset

```

## MCP server setup

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

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/OyyQuL7khcILyPEUV/builds/BiC2rizSQNTiaegtn/openapi.json
