Read job postings live from employer career sites across 10 applicant tracking systems.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Working code for pulling job postings straight out of company applicant tracking systems β Greenhouse, Lever, Workday, Ashby, Workable, SmartRecruiters, Breezy, Personio, Recruitee, BambooHR, Pinpoint and Rippling β and doing something useful with them.
Which ATS API gives you what β salary, posting dates and remote flags across all twelve platforms, measured across 1,549,353 live postings. Nothing else publishes these numbers, so start there if you are choosing which platform to build on.
Every script here runs as-is. Set APIFY_TOKEN and go.
Each of these platforms publishes an open JSON endpoint that the company's own careers page reads β no key, no login, no scraping of rendered HTML. The awkward parts are everything around that:
"Posted 30+ Days Ago"; SmartRecruiters caps a
response at 100 rows whatever limit you pass; Breezy answers 403 for a board that does not
exist, where everyone else uses 404.The scripts below use Apify Actors that have already dealt with all of that and return one row shape across every platform. You can equally point them at the raw endpoints β the notes at the bottom list them.
| File | What it does |
|---|---|
javascript/watch-companies.mjs | Diff a shortlist between runs β what opened, what closed |
javascript/salary-data.mjs | Postings that publish a pay range, normalised to an annual figure |
python/one_company.py | Every open role at one company, from its careers URL |
python/new_jobs_to_csv.py | Only postings that appeared since the last run, appended to CSV |
These Actors bill per row delivered. Every script caps itself at a couple of hundred rows and
reads MAX_ROWS if you want more, so running an example does not produce a surprise.
Every recipe gets the same fields, whichever platform the job came from:
companySlug:jobId is stable while a posting is open, which is what makes the diffing recipes work.
Measured from live boards, not from vendor documentation. Useful before you build on any one of them:
The same table, with the reasoning behind each column, is on the full reference page.
| Platform | Posting date | Description | Pay | Marked remote |
|---|---|---|---|---|
| Workday | 78.2% | no | no | no |
| SmartRecruiters | yes | no | no | 7.7% |
| Greenhouse | yes | yes | no | no |
| Workable | yes | yes | no | 36.3% |
| BambooHR | no | no | no | no |
| Lever | yes | 94.7% | no | 4.8% |
| Breezy HR | yes | no | 45.7% | 15.7% |
| Personio | no | no | no | 8.8% |
| Ashby | yes | yes | 38.9% | 54.2% |
| Recruitee | yes | yes | 26.9% | 9.9% |
| Rippling | no | no | no | 17.4% |
| Pinpoint | no | yes | 42.5% | 8.8% |
title, company, location and applyUrl come back on every row from every platform.
These are measured numbers, not a feature matrix. Each row is every live board this project
tracks for that platform β between 17,000 and 179,000 postings per platform, measured 2026-08-20.
yes means 99.5% or more; no means the endpoint carries no such field at all.
Three things the table is telling you:
If you would rather call the platforms directly, these are the public endpoints. All of them answer
without a key. Replace {company} with the board slug.
| Platform | Endpoint |
|---|---|
| Greenhouse | https://boards-api.greenhouse.io/v1/boards/{company}/jobs?content=true |
| Lever | https://api.lever.co/v0/postings/{company}?mode=json |
| Ashby | https://api.ashbyhq.com/posting-api/job-board/{company}?includeCompensation=true |
| SmartRecruiters | https://api.smartrecruiters.com/v1/companies/{company}/postings?limit=100&offset=0 |
| Workable | https://apply.workable.com/api/v1/widget/accounts/{company}?details=true |
| Breezy | https://{company}.breezy.hr/json |
| Personio | https://{company}.jobs.personio.de/search.json |
| Pinpoint | https://{company}.pinpointhq.com/postings.json |
| Recruitee | https://{company}.recruitee.com/api/offers/ |
| BambooHR | https://{company}.bamboohr.com/careers/list |
| Rippling | https://api.rippling.com/platform/api/ats/v1/board/{company}/jobs |
| Workday | POST https://{tenant}.{cluster}.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobs |
Four things that will bite you if you write your own client:
limit. Page with
offset, and take the real total from totalFound rather than counting rows."0 USD hour" as a pay range. Treat min <= 0 && max <= 0 as absent./careers/list has no posting date, description or
compensation; those live on /careers/{id}/detail, one request per posting. And its isRemote
field exists but is never populated β across 50,616 postings measured, not one had it set.403, not 404, for a subdomain with no board on it. Treating that as rate
limiting and backing off turns a half-hour job into a fourteen-hour one.MIT. The Actors these scripts call are commercial and priced per row; the code here is not.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/career-site-job-feed-2)<a href="https://allmcps.com/mcp/career-site-job-feed-2"><img src="https://allmcps.com/api/badge/career-site-job-feed-2?style=directory" alt="Career Site Job Feed on AllMCPs" /></a>