ATS Jobs Scraper: Greenhouse, Lever, Workday & Ashby
Pricing
from $1.00 / 1,000 jobs
ATS Jobs Scraper: Greenhouse, Lever, Workday & Ashby
Scrape live job listings directly from Greenhouse, Lever, Workday & Ashby ATS boards. Pass company slugs, get clean unified job data. No login, no anti-bot, pay per job. Hiring signal & recruiting feeds. Use it as an MCP server in Claude, ChatGPT & AI agents.
Pricing
from $1.00 / 1,000 jobs
Rating
0.0
(0)
Developer
The Mine Works
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
0
Monthly active users
8 days ago
Last modified
Categories
Share
What does ATS Jobs Scraper do?
It pulls live job openings straight from the four applicant-tracking systems most employers actually post to: Greenhouse, Lever, Workday, and Ashby. Give it ["stripe", "notion", "palantir"] and it returns clean, unified job records: title, location, department, employment type, remote flag, posting URL, and timestamps, in one schema regardless of which ATS each company runs.
Every one of these boards is a first-party source: the employer's own public listing, not a consumer job board's copy of it. No login, no CAPTCHA, no API key.
✅ No login | ✅ No anti-bot fight | ✅ First-party ATS source | ✅ MCP-ready for AI agents
Guide and FAQs: ATS Jobs Scraper on themineworks.com. Tutorial: Greenhouse vs Lever vs Ashby: Public Job APIs Compared.
Who is it for?
Recruiters and sourcers who want a live read on who is hiring for what, before it shows up on LinkedIn or Indeed. Sales teams building hiring-signal account lists, a company that just opened five engineering roles is a company with new budget. Market and competitive intelligence teams tracking hiring velocity by function. AI agents that need to answer "who is hiring for X right now" with real data.
How does it work across four different ATS platforms?
Every one of these four systems exposes its job postings through a public JSON API, not an HTML page, so this actor talks to each one in its native format and normalizes the result into a single schema. None of the four needs a proxy: every request is a plain HTTP call to the ATS's own API host, no browser, no residential IP, no anti-bot evasion required, because none of these four gate their public postings behind one.
- Greenhouse:
boards-api.greenhouse.io/v1/boards/<slug>/jobs?content=true, a single call returns every open job including the full description, keyed off the company's own slug (e.g.stripe). - Lever:
api.lever.co/v0/postings/<slug>, paginated 200 rows at a time for large boards. - Ashby:
api.ashbyhq.com/posting-api/job-board/<slug>, one call per company. - Workday: no public slug exists. Every Workday customer runs its own tenant on its own numbered datacentre (
https://<tenant>.wd<N>.myworkdayjobs.com/<site>), and neither the datacentre number nor the site name can be derived from a company name. So Workday is explicit-only: you pass the company's actual careers URL, and the actor parses the tenant, datacentre, and site from it. Workday's list endpoint also does not include the job description, so getting the full text costs one extra request per job, made only whenincludeDescriptionis on.
For companies, the actor tries Greenhouse first, then Lever, then Ashby, in that order, and keeps whichever one actually returns jobs, so you do not need to already know which system a company uses. Because the data comes from the employer's own board, there is no duplication across aggregators and no stale listings.
🧾 What input does it take?
Pass plain company slugs in companies and the ATS is auto-detected. Use boards when you already know the ATS, or for Workday, which cannot be auto-detected.
{"companies": ["stripe", "notion"],"boards": [{ "ats": "workday", "slug": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" }],"maxJobsPerCompany": 100,"includeDescription": true,"locationFilter": "United States","departmentFilter": "Engineering","remoteOnly": false}
| Input | Required | What it does |
|---|---|---|
companies | No* | Plain slugs. Tries Greenhouse, then Lever, then Ashby, and keeps the first that returns jobs. |
boards | No* | { "ats": "greenhouse" | "lever" | "ashby" | "workday", "slug": "..." }. Skips auto-detect. Workday's slug is its full careers URL. |
maxJobsPerCompany | No | Caps jobs returned per employer, default 500, maximum 2000. Also caps cost. |
includeDescription | No | Adds the full posting body (plain text and raw HTML). On Workday this costs one extra request per job. |
locationFilter | No | Only return jobs whose location contains this substring. |
departmentFilter | No | Only return jobs whose department contains this substring. Workday rows carry no department field and never match this filter. |
remoteOnly | No | Only return jobs flagged or worded as remote. |
*At least one of companies or boards must be set.
📤 What data do you get back?
Three real records from a single live run against companies: ["stripe", "notion", "palantir"], showing all three non-Workday board types in one call:
[{"ats": "greenhouse","company_slug": "stripe","job_id": "8172508","title": "Abuse Investigator","location": "Dublin","department": "8611 Security Analytics","remote": false,"url": "https://stripe.com/jobs/search?gh_jid=8172508","description": "Who we are. About Stripe. Stripe is a financial infrastructure platform for businesses. Millions of companies, from the world's largest enterprises to the most ambitious startups, use Stripe to accept payments, grow their revenue, and accelerate new business opportunities...","posted_at": "2026-09-03T13:32:53-04:00","updated_at": "2026-09-10T13:11:58-04:00","scraped_at": "2026-09-10T18:40:01.765Z"},{"ats": "ashby","company_slug": "notion","job_id": "1fc309c8-da20-4ff2-84c7-8b863ece2b0a","title": "Software Engineer, Developer Platform","location": "San Francisco, California","department": "Engineering","employment_type": "full-time","remote": true,"url": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a","description": "Notion is the collaborative AI workspace where teams and agents think together. We are building one place where your knowledge, projects, meetings, and AI tools live side by side, so work is faster, clearer, and less fragmented...","posted_at": "2026-08-24T14:44:49.699Z","updated_at": "2026-08-24T14:44:49.699Z","scraped_at": "2026-09-10T18:40:02.342Z"},{"ats": "lever","company_slug": "palantir","job_id": "ac978161-6f46-4f6b-ad9e-a258e642751c","title": "Administrative Business Partner","location": "London, United Kingdom","department": "Administrative","employment_type": "full-time","remote": false,"url": "https://jobs.lever.co/palantir/ac978161-6f46-4f6b-ad9e-a258e642751c","description": "Palantir builds the world's leading software for data-driven decisions and operations. By bringing the right data to the people who need it, our platforms empower our partners to develop lifesaving drugs, forecast supply chain disruptions, locate missing children, and more...","posted_at": "2024-03-25T21:50:16.463Z","scraped_at": "2026-09-10T18:40:03.124Z"}]
Every job record contains these fields:
| Field | Description |
|---|---|
🏷️ ats | ATS source: greenhouse, lever, workday, or ashby |
🏢 company_slug | Company slug on that ATS |
🆔 job_id | ATS internal job ID |
📄 title | Job title |
📍 location | Location string as posted |
🗂️ department | Department or team. Always empty on Workday rows, see Limitations |
⏱️ employment_type | Full time, contract, part time, or intern, when the ATS exposes a detectable value |
🌐 remote | Remote flag when the ATS marks it or the title/location says so |
🔗 url | Direct link to the public job posting |
📝 description | Plain text, truncated to 500 characters unless includeDescription is on |
📅 posted_at | Original posting date |
🔄 updated_at | Last update timestamp, when the ATS provides one |
🕒 scraped_at | ISO timestamp of capture |
When includeDescription is true, each record also carries description_html, the raw posting HTML. A field the source ATS does not expose (for example department on Workday) is omitted rather than sent as null.
What are the limitations?
Worth knowing before you buy, so there are no surprises:
- Workday needs the full careers URL, not a slug. A Workday slug does not exist as a derivable thing, the tenant's datacentre number and site name are unique per customer and cannot be guessed from the company name, so Workday is the one board here that cannot be auto-detected. See the input table above.
- Workday postings carry no department field. The public Workday board simply does not expose one, so
departmentis always empty on Workday rows anddepartmentFilternever matches them. This is not a bug in this actor; it is what Workday publishes. - Full descriptions on Workday cost one extra request per job. Workday's list endpoint has no description field, so
includeDescriptiontriggers a per-job detail call on Workday specifically. On the other three boards, the description already comes back in the same call. - Coverage is limited to these four systems. A company on a different or custom-built careers page will not be found. Auto-detect only tries Greenhouse, Lever, and Ashby, in that order.
- A large board takes longer.
maxJobsPerCompanybounds both cost and run time; a 2,000-job Workday pull with descriptions on means up to 2,000 sequential detail requests.
💼 What can you use it for?
Recruiting and talent research. Watch a portfolio of competitors and get notified the day they open a role worth going after. Build a live map of hiring in a niche, for example every backend role across a set of Series B companies.
Sales hiring signals. Trigger outbound the moment a target account opens a role in your ICP. Prioritize accounts that are hiring aggressively as a proxy for budget and growth.
Market and industry intelligence. Track hiring trends by function and location across a set of employers. Benchmark hiring velocity across competitors over time.
AI hiring copilots. Give an agent live ATS data so it can answer "who is hiring for X right now" with a real, current answer, and feed structured postings into a candidate-matching index.
🚀 How do I get started?
- Put company slugs in
companies, and the actor auto-detects the ATS, trying Greenhouse, then Lever, then Ashby. - For Workday, and for any company whose ATS you already know, use
boardsinstead. Workday is explicit-only, see the note above. - Set
maxJobsPerCompanyto cap volume and cost per employer. - Optionally set
locationFilter,departmentFilter, orremoteOnlyto narrow the run. - Toggle
includeDescriptionon if you need the full posting body. - Click Start, then download the dataset as JSON, CSV, or Excel, or pull it via API or MCP.
How much does it cost to scrape ATS jobs?
Pay per job actually delivered. The price is tiered by your Apify plan.
| Apify plan | Price per job | Price per 1,000 |
|---|---|---|
| Free | $0.00225 | $2.25 |
| Bronze | $0.0015 | $1.50 |
| Silver | $0.0012 | $1.20 |
| Gold and above | $0.0010 | $1.00 |
The Pricing tab on this page is the single source of truth and always shows the rate for your own plan. If this table and the Pricing tab ever disagree, the Pricing tab is right.
What a real job costs. Apify's Free plan includes $5 of usage credit every month, roughly 2,220 job postings at no cost to you. A 500-job pull across ten companies costs about $1.13 on Free, or about $0.50 on Gold.
What is never charged. A company with zero open roles, a board that returns nothing, or a company not found on any of the four supported systems costs nothing. The charge event fires only once a job record is actually in your dataset.
🔁 Can I run it on a schedule?
Yes, with Apify's built-in Schedules. No code and no cron server of your own. Competitor-hiring monitoring is this actor's natural mode: postings originate on the employer's own ATS board and syndicate outward from there, so polling the board directly is the earliest public signal.
- Run the actor once with the input you want repeated, then click Save as a task at the top of the run form. This keeps your exact input attached for every future run.
- In the Apify Console, go to Schedules in the left sidebar, then Create new.
- Name it, set your timezone, and pick a frequency: a preset (hourly, daily, weekly) or a cron expression such as
0 6 * * 1for weekly on Monday at 6am. - Under Actors or tasks to run, add the task you saved in step 1.
- Save. It then runs unattended, billed the same pay-per-job way as a manual run. Nothing is charged just for the schedule existing.
Wire the resulting dataset to Google Sheets, Slack, or a webhook through the actor's Integrations tab so new postings reach you automatically. Full schedule options, including time zones, run notifications and pausing, are in Apify's Schedules documentation.
Is scraping public ATS job postings legal?
This actor reads only public JSON endpoints that Greenhouse, Lever, Workday, and Ashby serve to any visitor, the same data your browser loads when you open a company's careers page. It does not log in to any of these systems, does not use cookies, and does not access anything behind an authentication wall.
That said, this is general information and not legal advice. A job posting can carry a recruiter's or hiring manager's name, which is personal data, so your obligations under GDPR, CCPA and similar laws apply to how you store and use it. You remain responsible for lawful use of the data you collect.
FAQ
How do I find a company's ATS slug?
Open the company's careers page and look at the URL. boards.greenhouse.io/stripe gives slug stripe, and the same pattern works for Lever (jobs.lever.co/notion) and Ashby (jobs.ashbyhq.com/scale). For those three you can skip this entirely and just pass the company name in companies; the actor auto-detects which board it is on.
Why does Workday need a full URL instead of a slug?
Because a Workday slug does not exist. Every Workday customer runs its own tenant on its own numbered datacentre, so the board lives at https://{company}.wd{N}.myworkdayjobs.com/{SiteName}, and neither the wd{N} number nor the site name can be derived from the company's name. Copy the careers URL straight from the employer's own careers page and pass it as the slug in boards.
Does every field come back for Workday?
Almost. Workday's public board carries no department field, so department is empty on Workday rows and departmentFilter will not match them. Description, employment type, posting date, and apply URL all come back in full when includeDescription is on.
Do any of the four boards need a proxy? No. All four are plain public JSON APIs read over a direct HTTP request, no browser and no residential proxy involved. That is a large part of why this actor is reliable: there is no anti-bot layer to work around on any of these four sources.
Do you scrape LinkedIn Jobs or Indeed? No. Consumer job boards are duplicative of the employer's own posting, often stale, and typically anti-bot walled. Reading straight from the employer's ATS gives you the canonical, first-party posting instead.
Can I get job postings before they appear on LinkedIn? Usually. Postings originate on the company's own ATS board and syndicate outward from there, so polling the ATS directly is the earliest public signal.
How do I track when a company opens a role in a specific department?
Schedule this actor with a departmentFilter, or filter downstream on title keywords, and diff against last week's dataset.
Can I use ATS Jobs Scraper through an MCP server? Yes. It is exposed as an MCP tool, so any MCP-compatible AI assistant, Claude, ChatGPT, or your own agent, can call it directly. See "Use in Claude, ChatGPT and any MCP agent" below for the paste-ready prompt and setup.
🤖 Use in Claude, ChatGPT and any MCP agent
Hosted MCP endpoint, no install, OAuth on first connect:
https://mcp.apify.com/?tools=themineworks/ats-jobs
Claude Desktop / Cursor config (token auth):
{"mcpServers": {"ats-jobs": {"url": "https://mcp.apify.com/?tools=themineworks/ats-jobs","headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }}}}
Ask your agent: "Check which of these 10 companies posted new engineering roles this week and summarize by location."
Copy this into your AI assistant
Paste the line below into ChatGPT, Claude, or any assistant connected to Apify's MCP, and it will run the job for you:
Use the Apify actor themineworks/ats-jobs to get open jobs at Stripe, Notion, and Palantir, and summarize them by department and location.
For the full recruiting stack in one connection, ATS boards plus LinkedIn jobs, profiles, and company data, see Recruiting & Jobs MCP, ten tools behind one endpoint.
Or call it programmatically with the Apify client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('themineworks/ats-jobs').call({companies: ['stripe', 'notion'],maxJobsPerCompany: 100,includeDescription: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
🛠️ Related actors
Pair this with the rest of the themineworks recruiting and sales suite:
- Recruiting & Jobs MCP: ten ATS, LinkedIn, and job-market tools behind one MCP endpoint.
- B2B Leads Finder: turn a hiring company into decision-maker emails and LinkedIn profiles.
- AmbitionBox Scraper: company reviews, salaries, and ratings for target employers.
- GitHub Repo Scraper: cross-check engineering hiring signals with public GitHub activity.
Typical flow: this actor surfaces the hiring event, B2B Leads Finder finds the right person to reach, AmbitionBox Scraper gives context on the employer.
Found a bug or have a feature request? Open an issue on the actor's Apify Console page.