# Greenhouse, Lever & Ashby Job Scraper: 8 ATS in One Feed (`rod_analytics/multi-ats-jobs-api`) Actor

Scrape jobs from Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Workday in one normalized feed. Search 181 well-known companies by keyword with presets, or paste your own. Salary, remote, only-new alerts. $1.20 per 1,000 jobs.

- **URL**: https://apify.com/rod_analytics/multi-ats-jobs-api.md
- **Developed by:** [Rod Services](https://apify.com/rod_analytics) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Features:** Limited permissions
- **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.
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

**Greenhouse, Lever and Ashby job scraper** with Workable, SmartRecruiters, Recruitee, Personio and Workday in the same normalized feed.
Search jobs by keyword across **181 well-known companies with one preset**, or paste your own company list. Salary, remote flag and only-new monitoring. **$1.20 per 1,000 jobs, no API key.**

### What you get

- **One feed from 8 ATS platforms**: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Workday. Every job has the same fields.
- **Company presets.** Pick AI, developer tools, fintech, European startups or Nordic tech, add a keyword such as `engineer`, and get matching jobs without building a company list.
- **Your own companies too.** Paste board URLs, `ats:slug` shorthands, careers pages or plain domains. The ATS is detected automatically.
- **Salary ranges** when the employer publishes them, **remote and hybrid flags**, departments, teams, locations and posting dates.
- **Full job descriptions** as clean text, optionally as HTML.
- **Only-new mode** for daily or hourly alerts: you get and pay for new jobs only.
- **Polite and key-free.** It reads the public job board APIs the employers publish. No login, no proxy.

### Company presets

| Preset | Companies | Examples |
| --- | --- | --- |
| `ai` | 42 | Anthropic, OpenAI, Scale AI, Databricks, Hugging Face, Cohere, Perplexity, ElevenLabs |
| `devtools` | 53 | GitLab, Vercel, Datadog, Cloudflare, MongoDB, Elastic, Supabase, Figma, Notion |
| `fintech` | 43 | Stripe, Plaid, Brex, Ramp, Mercury, Monzo, N26, Robinhood, Coinbase, Adyen |
| `eu-startups` | 34 | Celonis, GetYourGuide, Delivery Hero, HelloFresh, Doctolib, Alan, Back Market |
| `nordics` | 17 | Spotify, Wolt, Supercell, Mentimeter, Truecaller, Smartly.io, Oura, Pleo |
| `all` | 181 | Every company above, without duplicates |

Every preset board was checked against its ATS API on 2026-10-05. Boards can disappear when a company changes ATS. Such boards show up as `not-found` in `SUMMARY` and are free.

### Quick start

1. Open the **Input** tab. The prefill searches the `ai` preset for `engineer` and stops at 50 jobs.
2. Change the preset or the keywords, or paste your own companies into **Companies**.
3. Click **Start**. A preset search usually finishes in under a minute.
4. Open the **Output** tab and export to CSV, Excel or JSON, or read the dataset through the API.

For alerts, turn on **Only new jobs since last run** and add a daily schedule. Each run returns only jobs that were not delivered before.

### Input example

```json
{
    "presets": ["fintech", "eu-startups"],
    "companies": ["https://boards.greenhouse.io/gitlab", "lever:spotify", "notion.so", "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],
    "keywords": ["engineer", "data"],
    "locations": ["remote", "Germany"],
    "postedWithinDays": 14,
    "maxJobs": 500,
    "onlyNew": true
}
```

| Field | What it does |
| --- | --- |
| `presets` | Curated company lists: `ai`, `devtools`, `fintech`, `eu-startups`, `nordics` or `all`. |
| `companies` | Your own board URLs, `ats:slug`, careers page URLs or domains. Combined with presets. |
| `keywords` | Keep jobs whose title, department or team contains any word. Short words like AI or QA match whole words only. |
| `excludeKeywords` | Drop jobs whose title contains any word, for example intern or director. |
| `locations` | Keep jobs whose location contains any text. Add `remote` to include remote jobs. |
| `departments` | Keep jobs in matching departments or teams. |
| `remoteOnly` | Only remote jobs. |
| `postedWithinDays` | Only jobs first published in the last N days. |
| `maxJobs` | Stop after this many jobs in total. 0 = no limit. |
| `maxJobsPerCompany` | Cap per company after filters, newest first. 0 = all. |
| `onlyNew` | Return only jobs not returned in earlier runs. Seen IDs are kept per company in a named key-value store. |
| `stateStoreName` | Name of that store. Use one per schedule. |
| `includeDescription` | Plain text description, on by default. |
| `includeDescriptionHtml` | Original HTML description, off by default. |
| `probeSlugs` | If a careers page shows no ATS link, try the domain name on each ATS (stripe.com to stripe). |
| `maxConcurrency` | Companies processed in parallel, 5 by default. |

### Output sample

One dataset item per job.

```json
{
    "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
    "ats": "ashby",
    "company": "Ramp",
    "companySlug": "ramp",
    "title": "Security Engineer, Cloud",
    "department": "Engineering",
    "team": "Backend",
    "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
    "isRemote": true,
    "workplaceType": "hybrid",
    "employmentType": "full-time",
    "salaryMin": 211400,
    "salaryMax": 290600,
    "salaryCurrency": "USD",
    "salaryPeriod": "year",
    "postedAt": "2026-04-07T17:12:35.753Z",
    "updatedAt": null,
    "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
    "jobUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
    "descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams...",
    "fetchedAt": "2026-09-27T12:11:30.391Z"
}
```

A **SUMMARY** record in the key-value store lists every company with the detected ATS, board slug, detection method, job counts and errors. Two inputs that point to the same board are fetched and charged once.

### Data fields

| Field                                                      | Description                                                                         |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `jobId`, `ats`, `companySlug`                              | Stable ID per ATS board. `ats` + `companySlug` + `jobId` is unique.                 |
| `company`                                                  | Company name from the ATS.                                                          |
| `title`, `department`, `team`                              | Job title and org unit.                                                             |
| `locations[]`                                              | All locations.                                                                      |
| `isRemote`, `workplaceType`                                | Remote flag and remote / hybrid / onsite.                                           |
| `employmentType`                                           | full-time, part-time, contract, internship, or the ATS label.                       |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | Pay range when the employer publishes it (Greenhouse, Ashby, Lever, Recruitee).     |
| `postedAt`, `updatedAt`                                    | ISO 8601 dates. `updatedAt` only where the ATS provides it (Greenhouse, Recruitee). |
| `applyUrl`, `jobUrl`                                       | Apply form and public job page.                                                     |
| `descriptionText`, `descriptionHtml`                       | Full description as text and optional HTML.                                         |
| `fetchedAt`                                                | Time of the fetch.                                                                  |

### Supported ATS

| ATS | Board URL example | Salary | Remote flag | Notes |
| --- | --- | --- | --- | --- |
| Greenhouse | boards.greenhouse.io/gitlab | yes, when published | from location | EU boards supported |
| Lever | jobs.lever.co/spotify | yes, when published | yes | EU boards supported |
| Ashby | jobs.ashbyhq.com/linear | yes, when published | yes | compensation tiers mapped |
| Workable | apply.workable.com/huggingface | no | yes | one request per board |
| SmartRecruiters | careers.smartrecruiters.com/BoschGroup | no | yes | description needs one request per job |
| Recruitee | bunq.recruitee.com | yes, when published | yes | |
| Personio | holidu.jobs.personio.de | no | from office name | XML feed must be enabled by the employer |
| Workday | nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite | no | from location | paste the board URL; keywords are searched on Workday first |

Workday lists only relative dates such as "Posted 3 Days Ago". Every returned Workday job gets its exact date, all locations and the description from its job page. The `postedWithinDays` filter runs on the list date, so it drops jobs listed as "30+ days ago". Large Workday boards list up to 2,000 jobs and take a minute or two without keywords. Teamtailor and iCIMS are not supported.

### Pricing

Pay per event. Discounts apply automatically on paid Apify plans.

| Event | Free plan | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| Job, per 1,000 | $1.20 | $1.08 | $0.96 | $0.84 |
| Company detected from a careers page or domain, each | $0.002 | $0.0018 | $0.0016 | $0.0014 |
| Run start, per run | $0.001 | $0.001 | $0.001 | $0.001 |

- Presets, board URLs and `ats:slug` inputs are never charged a detection fee.
- Filtered-out jobs, duplicates and companies that are not found are free.
- Comparable job APIs in the Apify Store charge about $1.50 to $12 per 1,000 jobs on the Free plan, checked on 2026-10-05.
- Set **Maximum cost per run** or **Max jobs in total** to cap spend.

### Use cases

- **Job boards and aggregators.** Fill a niche board, for example AI jobs or remote fintech jobs, from presets and keywords.
- **Hiring signals for sales.** Track which companies open sales, data or security roles, and reach out while budgets are fresh.
- **Recruiting and talent intelligence.** Watch competitors' openings, salary ranges and locations.
- **AI agents and automations.** Call it through the Apify API, Make, Zapier, n8n or the Apify MCP server at `mcp.apify.com`.

```bash
curl -X POST "https://api.apify.com/v2/acts/rod_analytics~multi-ats-jobs-api/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" -H "Content-Type: application/json" \
  -d '{"presets": ["ai"], "keywords": ["engineer"], "remoteOnly": true, "maxJobs": 100}'
```

### FAQ

**Is it legal to scrape these job boards?** The Actor reads only the **public job board APIs** that each ATS offers so employers can publish jobs on their own sites. Greenhouse states job board data is publicly available. Lever states published postings "may be scraped by third parties". No login, key or protection is bypassed. You are responsible for how you use the data.

**Personal data?** Recruiter names and job inbox addresses are dropped. Personal-looking email addresses inside descriptions are replaced with `[email removed]`. Names that employers write into description text are not removed.

**Why was my company not found?** The careers page may use an unsupported ATS (Teamtailor, iCIMS, SAP, own system) or load jobs only after login. Check `SUMMARY`. If you know the board URL, pass it directly.

**Can slug guessing pick the wrong company?** Rarely, two companies can share a slug. Boards whose company name clearly differs from the domain are skipped. Boards that publish no company name (some Personio, Lever and Ashby boards) can still match another company with the same name. Check `companySlug` and `company`, or pass the board URL.

**What happens if my input is wrong or nothing matches?** The run ends **SUCCEEDED** with one free help row: `error`, `errorCode` (`INVALID_INPUT` or `NO_RESULTS`), `message` and `howToFix`. Only the start fee is charged. In `onlyNew` mode an empty run is normal and writes no help row.

**Feedback or a custom ATS?** Open an issue in the **Issues** tab. Replies usually come within a day.

### Related Actors

| Actor | What it does |
| --- | --- |
| [Website Content Crawler to Markdown for RAG & LLMs](https://apify.com/rod_analytics/website-to-markdown) | Crawl a site and get clean Markdown for RAG and LLMs |
| [PDF to Markdown & Text Extractor with OCR](https://apify.com/rod_analytics/doc-to-markdown) | Turn PDF, DOCX and scans into Markdown or text |
| [SEO Audit Tool: Site Crawler, Broken Links & Score](https://apify.com/rod_analytics/seo-site-audit) | Crawl a site for broken links and SEO issues |
| [PageSpeed Insights & Lighthouse Bulk Checker](https://apify.com/rod_analytics/lighthouse-audit) | Core Web Vitals and Lighthouse scores for many URLs |
| [Tech Stack Detector: Wappalyzer & BuiltWith Alternative](https://apify.com/rod_analytics/tech-stack-detector) | See which CMS, analytics and frameworks a site uses |
| [Bulk Domain Lookup: DNS, WHOIS, SPF, DMARC & SSL](https://apify.com/rod_analytics/domain-security-audit) | DNS, mail security and SSL checks for domain lists |
| [Speech to Text: Audio, Video & Podcast Transcriber](https://apify.com/rod_analytics/media-transcriber) | Transcribe audio, video and podcasts |
| [Email Validator & Verifier: Bulk MX & Disposable Check](https://apify.com/rod_analytics/bulk-email-verifier) | Clean email lists before you send |
| [Website Contact Scraper: Emails, Phones & Social Links](https://apify.com/rod_analytics/company-contact-extractor) | Emails, phones and social links from company websites |
| [VIES VAT Checker & EU Company Registry Lookup](https://apify.com/rod_analytics/eu-company-lookup) | Validate EU VAT numbers and look up companies |
| [Companies House Scraper: UK Company Search & Officers](https://apify.com/rod_analytics/uk-companies-house) | UK company profiles, officers and filings |
| [EU TED Tenders Scraper & Alerts: Public Procurement](https://apify.com/rod_analytics/ted-tenders) | EU public tenders with daily alerts |
| [GitHub Scraper: Repo Stats, Stars, Trending & Search](https://apify.com/rod_analytics/github-repo-stats) | Stars, activity and trending GitHub repos |

# Changelog

This Actor's version history is a separate document: https://apify.com/rod_analytics/multi-ats-jobs-api/changelog.md

# Actor input Schema

## `presets` (type: `array`):

Curated lists of well-known companies and their job boards, so you can search jobs by keyword without a company list. Combine with Keywords below. 'All presets' covers 181 companies.

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

Your own companies, one per line, in addition to any preset. Accepted: an ATS board URL (https://boards.greenhouse.io/gitlab, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/linear, https://apply.workable.com/acme, https://careers.smartrecruiters.com/Acme, https://acme.recruitee.com, https://acme.jobs.personio.de, https://acme.wd5.myworkdayjobs.com/External), a shorthand like greenhouse:gitlab or lever:spotify, a careers page URL (https://linear.app/careers) or a company domain (figma.com). For careers pages and domains the ATS is detected automatically, which is charged as one "company detected" event.

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

Keep jobs whose title, department or team contains any of these words, for example engineer, sales, designer. Case-insensitive. Words of 3 letters or less (AI, QA, Go) must match a whole word. Empty = all jobs.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains any of these words, for example intern, senior, director.

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

Keep jobs whose location contains any of these texts, for example Berlin, Germany, London, United States. Add "remote" to also keep remote jobs.

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

Keep jobs whose department or team contains any of these texts, for example Engineering, Sales, Marketing.

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

Keep only jobs marked remote by the ATS or with "remote" in the location.

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

Keep jobs first published in the last N days. Jobs without a publish date are dropped when this is set. 0 = no limit.

## `maxJobs` (type: `integer`):

Stop after this many jobs in total, across all companies. Handy with presets and broad keywords. 0 = no limit.

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

Cap the number of jobs returned per company after filters. The newest jobs are kept. 0 = no limit.

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

Remember job IDs per company in a named key-value store and return only jobs not returned in earlier runs. Use it with a daily or hourly schedule. You pay only for new jobs.

## `stateStoreName` (type: `string`):

Named key-value store that keeps seen job IDs for "Only new jobs". Use a different name per schedule or task to keep their histories apart. Letters a-z, digits and dashes.

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

Add the full job description as clean plain text (descriptionText). Turn off for smaller, faster runs.

## `includeDescriptionHtml` (type: `boolean`):

Also add the original description HTML (descriptionHtml).

## `probeSlugs` (type: `boolean`):

When a careers page shows no ATS link, try the company name from the domain (stripe.com -> stripe) on each supported ATS API. Finds most JavaScript-only careers pages. Can match a different company with the same name, check companySlug in the output.

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

How many companies are processed at the same time. Requests to each ATS host are always limited to 2 per second.

## Actor input object example

```json
{
  "presets": [
    "ai"
  ],
  "keywords": [
    "engineer"
  ],
  "excludeKeywords": [],
  "locations": [],
  "departments": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "maxJobs": 50,
  "maxJobsPerCompany": 5,
  "onlyNew": false,
  "stateStoreName": "ats-jobs-seen",
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "probeSlugs": true,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `jobs` (type: `string`):

All jobs, one row per job.

## `salary` (type: `string`):

No description

## `details` (type: `string`):

No description

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

Detected ATS, board slug and job counts for every input, including the ones that could not be resolved.

# 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 = {
    "presets": [
        "ai"
    ],
    "keywords": [
        "engineer"
    ],
    "maxJobs": 50,
    "maxJobsPerCompany": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("rod_analytics/multi-ats-jobs-api").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 = {
    "presets": ["ai"],
    "keywords": ["engineer"],
    "maxJobs": 50,
    "maxJobsPerCompany": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("rod_analytics/multi-ats-jobs-api").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 '{
  "presets": [
    "ai"
  ],
  "keywords": [
    "engineer"
  ],
  "maxJobs": 50,
  "maxJobsPerCompany": 5
}' |
apify call rod_analytics/multi-ats-jobs-api --silent --output-dataset

```

## MCP server setup

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

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/D7zdynLWE59QfHkhd/builds/zO9yZgXYc1nddD7R3/openapi.json
