# ATS Job Postings — Greenhouse, Lever, Ashby (`khassinx/ats-jobs-scraper`) Actor

Fetch job postings from 363 companies' public ATS boards — Greenhouse, Lever and Ashby. Deduplicated across runs: you only pay for postings you haven't received before.

- **URL**: https://apify.com/khassinx/ats-jobs-scraper.md
- **Developed by:** [KHASSINX LLC](https://apify.com/khassinx) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 new job postings

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## ATS Job Postings Scraper — Greenhouse, Lever, Ashby · billed only for new postings

> **30 days, 100 companies.** A scraper that bills per row: ~40,000 rows a month → **$60** at $1.50/1,000 — and 95% of those are postings you already saw. Here: ~2,000 genuinely new postings → **$4**. The more often you run it, the cheaper it gets.

Fetch job postings from companies' **public ATS job boards** and get them back in one consistent
shape, whichever system the company uses.

Built for a specific question — **did this company just start hiring** — which makes it more
useful to sales and lead-gen teams tracking that signal than to recruiters reading the postings
themselves.

### What makes it different

**You only pay for postings you haven't seen before.** The actor remembers what it delivered in
previous runs and skips it — so a daily run returns today's new openings, not the same list over
and over.

### Companies covered

**363 companies today — 272 Greenhouse · 77 Ashby · 14 Lever.** Press
**Start** and it runs against all of them. You don't need to know how any company configures its
careers page.

Narrow it down, or go beyond the catalog:

| Input | What it does |
|---|---|
| `catalog_tags` | Keep only companies matching a tag — `tech`, `fintech`, `ai`, `data`, `design` |
| `catalog_sources` | Keep only one ATS — `lever`, `greenhouse`, `ashby` |
| `catalog_limit` | Cap how many companies get queried in a single run |
| `targets` | Query any company by its board identifier, whether or not it's in the catalog: `[{ "source": "lever", "company": "palantir" }]` |
| `max_postings` | Hard cap on how many postings a run delivers — and therefore what it costs. Defaults to 2500 (about $5.00) |

### Output

Every posting comes back in the same shape, no matter the source:

```json
{
  "source": "greenhouse",
  "company": "stripe",
  "job_id": "4567",
  "title": "Backend Engineer",
  "location": "New York, NY",
  "url": "https://boards.greenhouse.io/stripe/jobs/4567",
  "posted_at": "2026-08-01T10:00:00-04:00",
  "department": "Engineering",
  "description_html": "<p>…</p>"
}
```

### What a real run looks like

Measured, not estimated — a run against the full catalog on 22 Aug 2026:

| | |
|---|---|
| Companies queried | 298 |
| Postings found | 55,325 |
| Postings **delivered** | 7,905 |
| Time | 5 minutes |

The gap between *found* and *delivered* is the whole point: the other 47,420 had already been
delivered in earlier runs, so they cost nothing. **On your first run everything is new — after
that, you pay for the difference.**

### Sources

All three sources are public, unauthenticated endpoints that their own documentation or
`robots.txt` permits. Systems whose terms prohibit automated extraction aren't supported —
that rules out Workday and SmartRecruiters.

### How it behaves

- **Identifies itself** on every request, with a real contact address. No browser spoofing.
- **Stays under published rate limits** and backs off on `429` instead of hammering.
- **A failing source never takes down the others** — if one board is down, the rest still return.

### Running it on a schedule

The point of paying only for new postings is running often. Open the actor's **Schedules** tab
and create one — daily, weekly, your call. **Run the actor manually at least once first**:
Apify requires a prior run before it lets you schedule one.

To be notified when a run brings something new, add an email or Slack notification from the
actor's **Integrations** tab. Runs that find nothing new still finish quietly, so a notification
tied to new results only reaches you when there is something to see.

***

Built by **KHASSINX LLC**.

# Actor input Schema

## `max_postings` (type: `integer`):

Safety cap on how many postings a single run delivers — and therefore what it costs you. Defaults to 2500 (about $5.00). Nothing is lost when the cap is hit: the next run picks up exactly where this one stopped, and you are never charged twice for the same posting.

## `catalog_tags` (type: `array`):

Only fetch companies matching these tags. Leave empty to fetch the whole catalog. Examples: tech, fintech, ai, data, design, saas, devtools, infra, consumer, retail, health, education, media, gaming, remote.

## `catalog_sources` (type: `array`):

Only fetch companies hosted on these applicant tracking systems. Leave empty for all three.

## `catalog_limit` (type: `integer`):

Caps how many companies are queried in a single run. Leave empty for no cap.

## `targets` (type: `array`):

Query exact companies instead of the built-in catalog. Each item: { "source": "lever" | "greenhouse" | "ashby", "company": "board-token" }. When set, the catalog filters above are ignored.

## Actor input object example

```json
{
  "max_postings": 2500,
  "catalog_tags": [
    "fintech"
  ],
  "catalog_sources": [
    "greenhouse"
  ],
  "catalog_limit": 5,
  "targets": [
    {
      "source": "greenhouse",
      "company": "stripe"
    },
    {
      "source": "lever",
      "company": "palantir"
    }
  ]
}
```

# Actor output Schema

## `postings` (type: `string`):

Every job posting found, normalized to one shape regardless of which ATS it came from. Postings already delivered in a previous run are not included and are not charged.

# 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 = {
    "max_postings": 2500,
    "catalog_tags": [
        "fintech"
    ],
    "catalog_sources": [
        "greenhouse"
    ],
    "catalog_limit": 5,
    "targets": [
        {
            "source": "greenhouse",
            "company": "stripe"
        },
        {
            "source": "lever",
            "company": "palantir"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("khassinx/ats-jobs-scraper").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 = {
    "max_postings": 2500,
    "catalog_tags": ["fintech"],
    "catalog_sources": ["greenhouse"],
    "catalog_limit": 5,
    "targets": [
        {
            "source": "greenhouse",
            "company": "stripe",
        },
        {
            "source": "lever",
            "company": "palantir",
        },
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("khassinx/ats-jobs-scraper").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 '{
  "max_postings": 2500,
  "catalog_tags": [
    "fintech"
  ],
  "catalog_sources": [
    "greenhouse"
  ],
  "catalog_limit": 5,
  "targets": [
    {
      "source": "greenhouse",
      "company": "stripe"
    },
    {
      "source": "lever",
      "company": "palantir"
    }
  ]
}' |
apify call khassinx/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khassinx/ats-jobs-scraper"
        }
    }
}

```

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/xqzrjqAnfnXOdkgZB/builds/kbc3CIDod9HwXPs1c/openapi.json
