# ATS Jobs Scraper API — Greenhouse, Lever, Ashby & 4 more (`spherical_tact/greenhouse-lever-ashby-jobs`) Actor

Live jobs from Greenhouse, Lever, Ashby, Workable, Recruitee, SmartRecruiters and Personio boards in one schema: annualized salary, remote/hybrid, seniority, tech stack. Ready-made company lists, hiring-signal summaries. $1/1K jobs.

- **URL**: https://apify.com/spherical_tact/greenhouse-lever-ashby-jobs.md
- **Developed by:** [DH](https://apify.com/spherical_tact) (community)
- **Categories:** Jobs, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 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/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

## ATS Jobs Scraper API — Greenhouse, Lever, Ashby, Workable, Recruitee, SmartRecruiters & Personio

Pull **live job postings** straight from company career boards on **7 applicant tracking systems** and get them back in **one clean schema** — with salary ranges **annualized**, plus **remote / hybrid / onsite**, **seniority**, **job category** and **tech stack** on every row.

- **7 ATS, one input.** Greenhouse, Lever, Ashby, Workable, Recruitee, SmartRecruiters and Personio. Paste board names (`stripe`), `ats:name` (`smartrecruiters:Wise`), careers URLs or domains — the ATS is auto-detected.
- **No company list? Use a preset.** Verified, ready-made lists: **AI & ML labs**, **developer tools & infra**, **fintech**, **security**, **crypto**, **consumer tech**, **European startups**, **remote-first companies**. Pick one and run.
- **Salary you can filter on.** Uses the ATS's structured pay range when the company publishes one, otherwise the first salary range in the description. Hourly and monthly pay are annualized, so `minAnnualSalary: 150000` just works.
- **Hiring signals per company.** Switch `outputMode` to `companies` to get one row per company: open jobs, new jobs in the last 7/30 days, top departments, seniority and work-mode mix, salary disclosure rate and medians, top tech stack, latest titles.
- **Fresh, not a stale index.** Every run reads the company's public job board API directly, so closed roles never show up.
- **Cheap and fast.** No AI and no browser. **$1.00 per 1,000 jobs.**
- **Built for monitoring.** Turn on `onlyNew` and schedule the Actor to get only postings you haven't seen yet.

### Who is it for

- **Job seekers, job boards & newsletters** — track target companies and filter by salary, level, remote and tech stack.
- **Sales, recruiting & VC (hiring signals)** — see which companies are growing which teams right now, and how fast.
- **Analysts & researchers** — compare pay ranges, remote policies and tech stacks across companies.
- **AI agents** — call it through the Apify MCP server to answer "who is hiring senior Rust engineers remotely?" with live data.

### Quick start

**1. A preset, filtered** — remote senior engineering jobs at AI companies that publish a salary:

```json
{
  "companyPresets": ["ai_ml"],
  "categories": ["software_engineering", "ml_ai"],
  "seniority": ["senior", "staff", "principal"],
  "workModes": ["remote"],
  "requireSalary": true,
  "maxItems": 300
}
```

**2. Your own companies** — any mix of ATS:

```json
{
  "companies": ["stripe", "https://jobs.lever.co/spotify", "ashby:openai", "smartrecruiters:Canva", "workable:huggingface"],
  "keywords": ["engineer"],
  "minAnnualSalary": 150000,
  "maxItems": 200
}
```

**3. Hiring signals** — one row per fintech company:

```json
{
  "companyPresets": ["fintech"],
  "outputMode": "companies"
}
```

### Supported ATS

| ATS | Input examples | Salary field | Work mode field |
|---|---|---|---|
| Greenhouse | `stripe`, `greenhouse:stripe`, `job-boards.greenhouse.io/figma` | pay transparency ranges | some boards |
| Lever | `lever:spotify`, `jobs.lever.co/spotify` | salary range | ✓ |
| Ashby | `ashby:openai`, `jobs.ashbyhq.com/ramp` | compensation | ✓ |
| Workable | `workable:huggingface`, `apply.workable.com/huggingface` | from description | remote flag |
| Recruitee | `recruitee:bunq`, `bunq.recruitee.com` | salary range | ✓ |
| SmartRecruiters | `smartrecruiters:Wise`, `jobs.smartrecruiters.com/Canva` | from description | ✓ |
| Personio | `personio:acme`, `acme.jobs.personio.de` | from description | from description |

Plain names are tried in the order above; when several ATS have a board with that name, the one whose company name matches wins. **For speed and certainty, use `ats:name`.**

### Company presets

| Preset | What's inside |
|---|---|
| `ai_ml` | AI labs and AI-first companies (model builders, AI apps, AI infra, robotics) |
| `devtools_infra` | Developer tools, databases, cloud & observability |
| `fintech` | Payments, banking, spend management, wealth |
| `security` | Cloud, identity, application and offensive security |
| `crypto_web3` | Exchanges, infrastructure and protocols |
| `consumer_tech` | Well-known consumer apps and marketplaces |
| `europe` | European scale-ups |
| `remote_first` | Companies known for distributed teams |

Every board in a preset was checked to exist and have open jobs when the list was built. Combine presets with your own `companies` — duplicates are removed. A whole preset can return thousands of jobs, so set `maxItems` or filters.

### Input

| Field | What it does |
|---|---|
| `companies` | Board names, `ats:name`, careers URLs or domains. Up to 500 per run (presets included). |
| `companyPresets` | Ready-made lists (see above). |
| `outputMode` | `jobs` (default, one row per job) or `companies` (one hiring-signal row per company). |
| `keywords` / `excludeKeywords` | Title (and department/team) word-start match. |
| `departments`, `locations` | Word-start match on department/team and on location/country. |
| `workModes` | `remote`, `hybrid`, `onsite`, `unspecified`. |
| `seniority` | `intern` … `executive`, `unspecified` (title first, then the ATS experience level). |
| `categories` | `software_engineering`, `data`, `ml_ai`, `devops_infra`, `security`, `product`, `design`, `research`, `sales_marketing`, `operations`, `hardware`, `other`. |
| `employmentTypes` | `full_time`, `part_time`, `contract`, `internship`. |
| `techStack` | Any of these technologies (aliases unified: Postgres = PostgreSQL, k8s = Kubernetes). |
| `minAnnualSalary`, `salaryCurrencies`, `requireSalary` | Salary filters (jobs without a salary are dropped when used). |
| `postedAfter` | `2026-09-15` or `7 days`. |
| `descriptionFormat` | `text` (default), `html`, `both`, `none`. |
| `onlyNew` | Return only jobs you haven't received with the same input (jobs mode). |
| `maxItems`, `maxItemsPerCompany` | Cap rows (and cost). |

### Output

#### Jobs (`outputMode: jobs`)

One row per job posting (30 fields):

```json
{
  "job_id": "ashby:openai:3c67f712-697d-48d8-b05c-01be896e61da",
  "ats": "ashby",
  "company_name": "OpenAI",
  "title": "Software Engineer, Scaled Abuse",
  "department": "Applied AI",
  "category": "software_engineering",
  "seniority": "unspecified",
  "employment_type": "full_time",
  "work_mode": "hybrid",
  "location": "San Francisco",
  "country": "United States",
  "posted_at": "2026-06-08T16:15:58+00:00",
  "salary_min": 266000,
  "salary_max": 445000,
  "salary_currency": "USD",
  "salary_period": "year",
  "salary_annual_min": 266000,
  "salary_annual_max": 445000,
  "salary_source": "ats_field",
  "tech_stack": ["Python", "PostgreSQL", "Kafka", "Azure", "Kubernetes", "Terraform"],
  "job_url": "https://jobs.ashbyhq.com/openai/3c67f712-...",
  "apply_url": "https://jobs.ashbyhq.com/openai/3c67f712-.../application",
  "description_text": "ABOUT THE TEAM ..."
}
```

#### Companies (`outputMode: companies`)

One row per job board, summarizing the jobs that pass your filters:

```json
{
  "company_name": "Ramp",
  "ats": "ashby",
  "board_url": "https://jobs.ashbyhq.com/ramp",
  "open_jobs": 160,
  "matched_jobs": 160,
  "new_jobs_7d": 9,
  "new_jobs_30d": 55,
  "top_departments": [{"name": "Sales", "jobs": 62}, {"name": "Engineering", "jobs": 38}, {"name": "People & Talent", "jobs": 14}],
  "seniority": {"unspecified": 91, "manager": 22, "senior": 20, "junior": 7, "lead": 7, "director": 7, "intern": 5},
  "work_modes": {"hybrid": 130, "onsite": 16, "remote": 14},
  "top_locations": [{"name": "New York, NY (HQ)", "jobs": 137}, {"name": "San Francisco, CA", "jobs": 88}],
  "salary_disclosed_pct": 95.6,
  "salary_currency": "USD",
  "salary_annual_median_min": 166160,
  "salary_annual_median_max": 257050,
  "top_tech_stack": [{"name": "Python", "jobs": 30}, {"name": "Salesforce", "jobs": 27}, {"name": "SQL", "jobs": 23}],
  "latest_titles": [{"title": "Product Manager | Growth", "posted_at": "2026-10-06T16:01:26+00:00", "job_url": "https://jobs.ashbyhq.com/ramp/..."}]
}
```

*(Real output from 2026-10-07, shortened.)* A `SUMMARY` record in the run's key-value store lists open/matched counts per board and any boards that were not found or failed.

### Integrations

- **API & SDKs** — run it from Python, JavaScript or plain HTTP and read the dataset as JSON, CSV or Excel.
- **Schedules + `onlyNew`** — a daily feed of new postings; add a webhook to push them to Slack, email or your database.
- **n8n, Make, Zapier** — use the Apify app/node: "Run Actor" → "Get dataset items".
- **Clay & spreadsheets** — call the run-sync endpoint with a company list and map `companies`-mode fields into columns.
- **AI agents (MCP)** — add the Apify MCP server to Claude, Cursor or VS Code and let the agent call this Actor with filters.

### Pricing

- **Jobs mode: $1.00 per 1,000 jobs returned.**
- **Companies mode: $0.005 per company summary.**
- Plus a tiny start fee. You pay only for rows that match your filters — set `maxItems` to cap the cost of a run.

### How it works and limits

- Reads each company's **public job board API** (the same data the company's careers page uses). No login, no browser, no personal data.
- Seniority, category, work mode and tech stack are **rule-based** (title, ATS fields, dictionary match), so they're fast and free but not perfect. `unspecified` means the posting didn't say.
- Salary from descriptions takes the **first** salary range found; check `salary_source` and `salary_text`. Multi-zone ranges are merged into one min–max in the first listed currency.
- SmartRecruiters lists jobs without descriptions, so descriptions are fetched only for jobs that pass your title/location/date filters — narrow filters make big SmartRecruiters boards much faster.
- Workable limits request rates, so plain names (which may be checked on Workable) are slower than `ats:name`.
- Workday, iCIMS and Taleo are not supported (no public job board API).

### FAQ

**How do I find a company's board name?** It's the part of the careers URL after the domain: `job-boards.greenhouse.io/figma` → `figma`, `jobs.lever.co/spotify` → `spotify`, `jobs.ashbyhq.com/ramp` → `ramp`, `apply.workable.com/huggingface` → `huggingface`, `bunq.recruitee.com` → `bunq`, `jobs.smartrecruiters.com/Wise` → `Wise`, `acme.jobs.personio.de` → `acme`. Or just paste the URL.

**A company wasn't found.** It may use an ATS that isn't supported, or a different board name. Check `SUMMARY` → `not_found` and try the exact careers URL.

**Can I get only new jobs every day?** Yes: schedule the Actor with `onlyNew: true` and the same input.

**What data does it read?** Only the job board endpoints that companies publish openly for their careers pages and for job aggregators. It collects no personal data. Check that your use fits each ATS's and company's terms.

### Related

- [HN Who is Hiring — AI Structured Jobs](https://apify.com/spherical_tact/hn-who-is-hiring-ai): 12+ months of Hacker News job posts with salary, remote regions, visa and tech stack.
- [HN Who wants to be hired — AI Structured Candidates](https://apify.com/spherical_tact/hn-who-wants-to-be-hired): developers looking for work.

# Actor input Schema

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

One per line: board name ('stripe'), 'ats:name' ('lever:spotify', 'workable:huggingface', 'smartrecruiters:Wise'), a careers URL or a domain. Plain names are tried on Greenhouse, Lever, Ashby, Workable, Recruitee, SmartRecruiters, then Personio. Up to 500 per run (with presets).

## `companyPresets` (type: `array`):

Add curated, verified job boards without looking up names. Combine with companies and filters. Tip: set maxItems — a whole list can return thousands of jobs.

## `outputMode` (type: `string`):

'jobs' = one row per matching job. 'companies' = one summary row per job board: open and matching jobs, new in 7/30 days, top departments, seniority and work-mode mix, salary disclosure and medians, top tech stack, latest titles. Filters apply before summarizing.

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

Keep jobs whose title, department or team contains any of these, matched at word start ('engineer' also matches 'engineering', 'ml' does not match 'html'). Case-insensitive. Empty = all.

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

Drop jobs whose title contains any of these (word-start match).

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

Keep jobs whose department or team contains any of these (word-start match).

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

Keep jobs whose location text or country contains any of these (word-start match), e.g. 'London', 'United States', 'Remote', 'Germany'. Multi-location jobs match if any location matches.

## `workModes` (type: `array`):

From the ATS field when present (Lever, Ashby, some Greenhouse boards), otherwise from the location/title or an explicit sentence in the description. Include 'unspecified' to keep jobs that don't say.

## `seniority` (type: `array`):

Inferred from the job title (e.g. 'Senior', 'Staff', 'II', 'Head of'). Many titles carry no level, so include 'unspecified' to avoid missing jobs.

## `categories` (type: `array`):

Job family inferred from title (then department).

## `employmentTypes` (type: `array`):

From the ATS field when present, otherwise from the title (intern, part-time, contract).

## `techStack` (type: `array`):

Keep jobs whose title or description mentions any of these technologies. Aliases are unified (Postgres=PostgreSQL, k8s=Kubernetes, Golang=Go, React.js=React).

## `minAnnualSalary` (type: `integer`):

Keep jobs whose annualized salary maximum is at least this (hourly x2080, monthly x12), in the job's own currency. Jobs without a stated salary are dropped when this is set.

## `salaryCurrencies` (type: `array`):

Keep jobs whose salary is in these ISO codes, e.g. USD, EUR, GBP. Jobs without a salary are dropped when this is set.

## `requireSalary` (type: `boolean`):

Keep only jobs where a salary range was found (ATS pay field or a range in the description).

## `postedAfter` (type: `string`):

Keep jobs first published on or after this date: '2026-09-15' or relative like '7 days'. Lever and Ashby give the publish date; Greenhouse gives first_published.

## `descriptionFormat` (type: `string`):

Include the job description as plain text, HTML, both, or none (smaller output).

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

For scheduled runs: return only jobs you haven't received from this Actor with the same input. IDs are kept in a key-value store named 'ats-jobs-state' in your account.

## `maxItemsPerCompany` (type: `integer`):

Cap rows per job board (newest first). Empty = no cap.

## `maxItems` (type: `integer`):

Maximum number of rows (jobs, or company summaries in 'companies' mode) to return in total. Each row is billed, so this caps your cost. Empty = all matching.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "https://jobs.lever.co/spotify",
    "ashby:openai"
  ],
  "companyPresets": [
    "ai_ml"
  ],
  "outputMode": "jobs",
  "keywords": [
    "engineer",
    "data"
  ],
  "excludeKeywords": [
    "intern",
    "manager"
  ],
  "departments": [
    "Engineering"
  ],
  "locations": [
    "New York",
    "Remote"
  ],
  "workModes": [
    "remote",
    "hybrid"
  ],
  "seniority": [
    "senior",
    "staff",
    "unspecified"
  ],
  "categories": [
    "software_engineering",
    "data",
    "ml_ai"
  ],
  "employmentTypes": [
    "full_time"
  ],
  "techStack": [
    "Python",
    "PostgreSQL"
  ],
  "minAnnualSalary": 150000,
  "salaryCurrencies": [
    "USD"
  ],
  "requireSalary": false,
  "postedAfter": "14 days",
  "descriptionFormat": "text",
  "onlyNew": false,
  "maxItemsPerCompany": 50,
  "maxItems": 200
}
```

# Actor output Schema

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

All rows: matching jobs, or company summaries in 'companies' mode.

# 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.lever.co/spotify",
        "ashby:openai"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("spherical_tact/greenhouse-lever-ashby-jobs").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.lever.co/spotify",
        "ashby:openai",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("spherical_tact/greenhouse-lever-ashby-jobs").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.lever.co/spotify",
    "ashby:openai"
  ]
}' |
apify call spherical_tact/greenhouse-lever-ashby-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spherical_tact/greenhouse-lever-ashby-jobs"
        }
    }
}
```

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/2LOuPUJm19eIbXo3B/builds/ShI8SKhMvQAkEv6eh/openapi.json
