Working recipes for reading job postings from ATS public APIs
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/HwangByeongSeon/ats-job-feed-recipesTools overview
# ATS job feed recipes
[](https://allmcps.com/mcp/career-site-job-feed)
Working code for pulling job postings straight out of company applicant tracking systems —
Greenhouse, Lever, Workday, Ashby, Workable, SmartRecruiters, Breezy, Personio, Pinpoint and
Rippling — and doing something useful with them.
Every script here runs as-is. Set `APIFY_TOKEN` and go.
```bash
export APIFY_TOKEN=... # https://console.apify.com/settings/integrations
python python/new_jobs_to_csv.py
```
## Why this exists
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:
- **Every platform has a different shape.** Greenhouse nests offices and departments; Workday sends
a POST and reports posting age as the string `"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`.
- **Finding out who is on which platform is the actual work.** There is no public directory of
Greenhouse or Personio boards. The slug is in a careers URL somewhere, if you can find the
careers URL.
- **Dates are unreliable.** Three of these ten platforms publish no posting date at all, so any
"posted in the last N days" filter has to decide what to do with rows whose age is unknown.
The scripts below use [Apify Actors](https://apify.com/starbright_overlap) 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](#raw-endpoints) at the bottom list them.
## Recipes
| File | What it does |
|---|---|
| [`javascript/watch-companies.mjs`](javascript/watch-companies.mjs) | Diff a shortlist between runs — what opened, what closed |
| [`javascript/salary-data.mjs`](javascript/salary-data.mjs) | Postings that publish a pay range, normalised to an annual figure |
| [`python/one_company.py`](python/one_company.py) | Every open role at one company, from its careers URL |
| [`python/new_jobs_to_csv.py`](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.
## The row shape
Every recipe gets the same fields, whichever platform the job came from:
```json
{
"provider": "greenhouse",
"company": "Databricks",
"companySlug": "databricks",
"jobId": "7845321",
"title": "Staff Software Engineer",
"location": "San Francisco, CA",
"department": "Engineering",
"employmentType": "Full-time",
"remote": false,
"postedAt": "2026-08-14T09:12:00.000Z",
"applyUrl": "https://boards.greenhouse.io/databricks/jobs/7845321",
"salary": null,
"descriptionText": "...",
"scrapedAt": "2026-08-19T11:02:41.883Z"
}
```
`companySlug:jobId` is stable while a posting is open, which is what makes the diffing recipes work.
## What each platform actually publishes
Measured from live boards, not from vendor documentation. Useful before you build on any one of them:
| Field | Workday | SmartRecruiters | Greenhouse | Workable | Lever | Ashby | Breezy | Personio | Pinpoint | Rippling |
|---|---|---|---|---|---|---|---|---|---|---|
| title, company, location | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| applyUrl | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| postedAt | partial | yes | yes | yes | yes | yes | yes | no | no | no |
| department | no | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| employmentType | yes | yes | no | yes | yes | yes | yes | yes | yes | no |
| descriptionText | no | no | yes | yes | yes | yes | no | no | yes | no |
| salary | no | no | no | no | no | yes | yes | no | 37% | no |
Workday's `partial` is the `"Posted 30+ Days Ago"` problem: an exact age becomes a timestamp, a
vague one stays `null` rather than being invented.
## Raw endpoints
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` |
| Rippling | `https://api.rippling.com/platform/api/ats/v1/board/{company}/jobs` |
| Workday | `POST https://{tenant}.{cluster}.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobs` |
Two things that will bite you if you write your own client:
- **SmartRecruiters** returns at most 100 postings per response regardless of `limit`. Page with
`offset`, and take the real total from `totalFound` rather than counting rows.
- **Breezy** returns `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.
## Licence
MIT. The Actors these scripts call are commercial and priced per row; the code here is not.
What people ask about ats-job-feed-recipes
What is HwangByeongSeon/ats-job-feed-recipes?
+
HwangByeongSeon/ats-job-feed-recipes is tools for the Claude AI ecosystem. Working recipes for reading job postings from ATS public APIs It has 0 GitHub stars and its last recorded update is dated 2026-08-19.
How do I install ats-job-feed-recipes?
+
You can install ats-job-feed-recipes by cloning the repository (https://github.com/HwangByeongSeon/ats-job-feed-recipes) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is HwangByeongSeon/ats-job-feed-recipes safe to use?
+
Our security agent has analyzed HwangByeongSeon/ats-job-feed-recipes and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains HwangByeongSeon/ats-job-feed-recipes?
+
HwangByeongSeon/ats-job-feed-recipes is maintained by HwangByeongSeon. The last recorded GitHub activity is dated 2026-08-19, with 0 open issues.
Are there alternatives to ats-job-feed-recipes?
+
Yes. On ClaudeWave you can browse similar tools at /categories/tools, sorted by popularity or recent activity.
Deploy ats-job-feed-recipes to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/hwangbyeongseon-ats-job-feed-recipes)<a href="https://claudewave.com/repo/hwangbyeongseon-ats-job-feed-recipes"><img src="https://claudewave.com/api/badge/hwangbyeongseon-ats-job-feed-recipes" alt="Featured on ClaudeWave: HwangByeongSeon/ats-job-feed-recipes" width="320" height="64" /></a>More Tools
A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls.
An AI skill that provides design intelligence for building professional UI/UX across multiple platforms.
🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman
CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies
The best-benchmarked open-source AI memory system. And it's free.
The fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]