# Job Postings API – Greenhouse, Lever, Ashby & Workable Jobs (`scrapeworkshq/ats-jobs-scraper`) Actor

Job postings API for company career sites: get every open job from Greenhouse, Lever, Ashby, Workable and SmartRecruiters job boards in ONE unified format – title, location, remote, department, salary, posted date, apply URL, description. No login, no proxy.

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

## Pricing

Pay per event

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

## Job Postings API – Greenhouse, Lever, Ashby, Workable & SmartRecruiters Jobs Scraper

Pull **every open job** from company career boards hosted on **Greenhouse, Lever, Ashby, Workable and SmartRecruiters** – the applicant-tracking systems behind most tech, startup and enterprise career pages – and get them back in **one unified schema**: title, company, location(s), remote flag, workplace type, department/team, employment type, **salary range (when the company publishes it)**, posted date, job URL, apply URL and full description (text + HTML).

Uses each ATS's **official public job-board API** (the same feeds that power the companies' own careers pages). **No login, no API key, no proxy, no personal data.** Export to JSON, CSV, Excel or via the Apify API.

### 🚀 Quick start (60 seconds)

1. Click **Try for free** – the input is prefilled with a working example.
2. Press **Start**. A small run finishes in seconds and costs fractions of a cent.
3. Open the **Output** tab (table view) and export **CSV, Excel, JSON** or connect Google Sheets.

```json
{
  "companies": [
    "greenhouse:airbnb",
    "https://jobs.lever.co/palantir",
    "jobs.ashbyhq.com/ramp"
  ],
  "titleKeywords": [
    "engineer"
  ],
  "maxJobsPerCompany": 20
}
```

#### Sample output

| companyName | title | location | isRemote | department | postedAt | applyUrl |
|---|---|---|---|---|---|---|
| Hugging Face | Open-Source ML Engineer | Paris, France | true | Open Source | 2026-05-29 | apply.workable.com/j/81B46579FE |
| Airbnb | Senior Software Engineer | Remote - US | true | Engineering | 2026-10-14 | boards.greenhouse.io/airbnb/jobs/… |

### Why this job postings API / ATS jobs scraper?

| | This Actor | Typical single-ATS scrapers |
|---|---|---|
| Greenhouse + Lever + Ashby + Workable + SmartRecruiters in **one run** | ✅ | ❌ usually one ATS per Actor |
| **One unified output schema** across platforms | ✅ | ❌ different fields per tool |
| Bare company slug auto-detected across all 5 ATSs | ✅ | ❌ |
| Structured salary min/max/currency/interval (Ashby, Lever) | ✅ | rarely |
| Filters: title include/exclude, location, remote only, posted within N days | ✅ | partial |
| Full description as clean text **and** HTML | ✅ | often HTML only |
| No proxy needed → fast & cheap | ✅ | varies |
| Price | **$1.10 / 1,000 jobs** | $2.00 / 1,000 (most-used Greenhouse jobs Actor) |

### Use cases – job board aggregation, hiring signals & job alerts

- 🧲 **Job aggregators & niche job boards** – feed fresh postings from hundreds of companies daily.
- 📈 **Hiring-signal / sales intelligence** – detect which companies are hiring for which teams (e.g. "hiring first data engineer" = buying intent).
- 💰 **Salary benchmarking** – collect published pay ranges by title and location.
- 🔎 **Job seekers & recruiters** – monitor target companies, get alerted to new roles with `postedWithinDays: 1`.
- 🤖 **AI agents / RAG** – clean, consistent job JSON for LLM pipelines.

### Input

| Field | Description |
|---|---|
| `companies` | Career board URLs, `platform:slug`, or bare slugs (auto-detect). |
| `titleKeywords` / `excludeTitleKeywords` | Case-insensitive title filters. |
| `locationKeywords` | Keep jobs whose location contains any keyword. |
| `remoteOnly` | Only remote-flagged jobs. |
| `postedWithinDays` | Only jobs published in the last N days. |
| `includeDescription` | Include `descriptionText` + `descriptionHtml` (default on). |
| `maxJobsPerCompany`, `maxJobsTotal` | Limits (0 = unlimited). |

Accepted company formats:

```
greenhouse:airbnb              https://boards.greenhouse.io/airbnb   https://job-boards.greenhouse.io/stripe
lever:palantir                 https://jobs.lever.co/palantir
ashby:ramp                     https://jobs.ashbyhq.com/ramp
workable:huggingface           https://apply.workable.com/huggingface
smartrecruiters:BoschGroup     https://jobs.smartrecruiters.com/BoschGroup
notion                         (bare slug – tried on all 5 platforms)
```

Example:

```json
{
  "companies": ["greenhouse:stripe", "ramp", "https://jobs.lever.co/palantir"],
  "titleKeywords": ["engineer"],
  "excludeTitleKeywords": ["manager"],
  "locationKeywords": ["New York", "Remote"],
  "postedWithinDays": 30
}
```

### Output

One item per job (see `sample-output.json` for real examples from each platform):

```json
{
  "platform": "ashby",
  "companySlug": "ramp",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "companyName": "Ramp",
  "location": "New York, NY (HQ)",
  "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
  "isRemote": true,
  "workplaceType": "Hybrid",
  "department": "Engineering",
  "team": "Backend",
  "employmentType": "FullTime",
  "salaryMin": 211400,
  "salaryMax": 290600,
  "salaryCurrency": "USD",
  "salaryInterval": "1 YEAR",
  "salaryText": "$211.4K - $290.6K",
  "postedAt": "2026-04-07T17:12:35.753Z",
  "url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams…",
  "scrapedAt": "2026-10-21T21:43:55.300Z"
}
```

Fields not offered by a given ATS are `null` (e.g. Greenhouse and Workable public feeds don't publish structured salary; SmartRecruiters has no multi-location list). A `RUN_STATS` record in the key-value store summarizes companies found, jobs seen, filtered and saved.

### ⭐ Unique: Monitor mode, CSV-ready output & webhook summary

**New-job alerts & closed-job detection**: schedule daily with `monitorMode: "onlyNew"` and you get only jobs that weren't there yesterday (old ones are free). The `SUMMARY` record also lists `notSeenThisRun` – jobs that disappeared from the boards, i.e. were **closed or filled** – a hiring-signal no other ATS Actor gives you.

- **Monitor mode** (`monitorMode`: `all` | `changes` | `onlyNew`, plus `monitorKey`) – cross-run dedupe and field-level diffs (`changeType`, `changedFields`, `changes`, `firstSeenAt`). Skipped items cost **$0**.
- **Flat / CSV-ready output** (`outputFormat: "flat"`) – one column per field, perfect for Excel and Google Sheets.
- **Run summary** – a free `SUMMARY` record in the run's key-value store (also linked in the Output tab) and optionally POSTed to `summaryWebhookUrl`.
- **Changes** dataset view – see what's new/changed at a glance.

### 💰 Pricing (pay per result)

| Event | Price |
|---|---|
| Run start | $0.00005 |
| Job posting | **$1.10 / 1,000** |

≥25% cheaper than comparable ATS job Actors ($1.50–$3.00 / 1,000). One unified schema across 5 ATS platforms.

🎁 **Sweetener:** in Monitor mode you only pay for new/changed items, and duplicates within a run are never charged. Run summary + webhook are free.

### Tips

- Find a company's slug from its careers page URL (e.g. `boards.greenhouse.io/<slug>`, `jobs.lever.co/<slug>`).
- Schedule a daily run with `postedWithinDays: 1` for a new-jobs feed.
- SmartRecruiters descriptions need one extra request per job; turn off `includeDescription` for very large SmartRecruiters boards to go faster.

### Legal & privacy

This Actor reads only **public job postings** that companies publish through their ATS's public job-board APIs for distribution. It does not log in, does not access candidate/applicant data and collects **no personal data**. You are responsible for using the data in line with applicable laws and the sites' terms.

### 🔌 Integrations & API

Works with Zapier, Make, n8n, Google Sheets, Slack, Airbyte, LangChain/LlamaIndex and the Apify MCP server (AI agents).

**JavaScript**

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('scrapeworkshq/ats-jobs-scraper').call({"companies": ["greenhouse:airbnb", "https://jobs.lever.co/palantir", "jobs.ashbyhq.com/ramp"], "titleKeywords": ["engineer"], "maxJobsPerCompany": 20});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient('<APIFY_TOKEN>')
run = client.actor('scrapeworkshq/ats-jobs-scraper').call(run_input={"companies": ["greenhouse:airbnb", "https://jobs.lever.co/palantir", "jobs.ashbyhq.com/ramp"], "titleKeywords": ["engineer"], "maxJobsPerCompany": 20})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

**cURL (sync, returns items)**

```bash
curl -X POST 'https://api.apify.com/v2/acts/scrapeworkshq~ats-jobs-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>&format=csv' \
  -H 'content-type: application/json' -d '{"companies": ["greenhouse:airbnb", "https://jobs.lever.co/palantir", "jobs.ashbyhq.com/ramp"], "titleKeywords": ["engineer"], "maxJobsPerCompany": 20}'
```

### ❓ More FAQ

**Which ATS platforms are supported?**\
Greenhouse, Lever, Ashby, Workable and SmartRecruiters. Bare slugs are auto-detected.

**Is salary included?**\
Yes when the company publishes it (salaryMin/Max/Currency/Interval).

**How does Monitor mode work?**\
The Actor remembers the IDs and key fields of items it returned before (in a named key-value store in *your* account, keyed by `monitorKey`). Next run, each item gets `changeType` = `new` / `changed` / `unchanged` plus a `changes` diff. In *Only new* / *Only new or changed* modes, the rest is skipped **and not charged**.

**How do I get a clean CSV / Excel / Google Sheet?**\
Set **Output format → Flat / CSV-ready**. Nested objects become `dot.columns` and lists are joined with `|`, so every export is one row per item with no JSON blobs.

**Can I get notified when a run finishes?**\
Set **Summary webhook URL** (Zapier/Make/n8n catch hook, Slack workflow, your API). You receive one compact JSON: counts, new/changed, price drops/rises, dataset ID. Or use Apify's native webhooks/integrations.

**How do I limit cost?**\
Use the max-results inputs and Apify's *Maximum cost per run*. The Actor stops cleanly when the limit is reached.

Found a bug or need a field? Open an issue on the **Issues** tab – we usually reply within 24 h.

### Changelog

- **2026-10-21** – Monitor mode (new/changed only, free skips), flat CSV-ready output, SUMMARY record + webhook, Changes view.

# Actor input Schema

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

Career board URLs (boards.greenhouse.io/airbnb, jobs.lever.co/palantir, jobs.ashbyhq.com/ramp, apply.workable.com/huggingface, jobs.smartrecruiters.com/BoschGroup), "platform:slug" (e.g. greenhouse:stripe) or a bare slug (e.g. notion) – bare slugs are auto-detected across all 5 ATS platforms.

## `titleKeywords` (type: `array`):

Keep jobs whose title contains any of these words (case-insensitive), e.g. "engineer", "sales". Empty = all.

## `excludeTitleKeywords` (type: `array`):

Drop jobs whose title contains any of these, e.g. "intern", "senior".

## `locationKeywords` (type: `array`):

Keep jobs whose location(s) contain any of these, e.g. "New York", "Remote", "Germany".

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

Keep only jobs flagged remote by the ATS (or with 'remote' in the location).

## `postedWithinDays` (type: `integer`):

Only jobs first published in the last N days. 0 = any age. Great for daily new-job monitoring.

## `includeDescription` (type: `boolean`):

Adds descriptionText and descriptionHtml. Turn off for smaller, faster output.

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

0 = all open jobs.

## `maxJobsTotal` (type: `integer`):

0 = no overall limit.

## `maxConcurrency` (type: `integer`):

How many company boards to fetch at once.

## `monitorMode` (type: `string`):

Remembers items from previous runs (per Monitor key) and adds changeType = new/changed/unchanged plus a field-level diff. In the two 'only' modes, unchanged/old items are not output and not charged.

## `monitorKey` (type: `string`):

Name of the memory used by Monitor mode. Use a different key per schedule/task (e.g. 'daily-pokemon'), so separate watchlists don't mix.

## `outputFormat` (type: `string`):

Flat makes CSV/Excel/Google Sheets exports one clean column per field.

## `summaryWebhookUrl` (type: `string`):

At the end of the run, POST a compact JSON summary (counts, new/changed, price drops, dataset ID) to this URL – e.g. Zapier/Make/n8n catch hook or Slack workflow. Free.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:airbnb",
    "https://jobs.lever.co/palantir",
    "jobs.ashbyhq.com/ramp"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeDescription": true,
  "maxJobsPerCompany": 20,
  "maxJobsTotal": 0,
  "maxConcurrency": 4,
  "monitorMode": "off",
  "monitorKey": "default",
  "outputFormat": "full"
}
```

# Actor output Schema

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

All scraped items in the default dataset

## `overview` (type: `string`):

No description

## `summary` (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": [
        "greenhouse:airbnb",
        "https://jobs.lever.co/palantir",
        "jobs.ashbyhq.com/ramp"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapeworkshq/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 = {
    "companies": [
        "greenhouse:airbnb",
        "https://jobs.lever.co/palantir",
        "jobs.ashbyhq.com/ramp",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapeworkshq/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 '{
  "companies": [
    "greenhouse:airbnb",
    "https://jobs.lever.co/palantir",
    "jobs.ashbyhq.com/ramp"
  ],
  "maxJobsPerCompany": 20
}' |
apify call scrapeworkshq/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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