Almost every tech company's job board runs on one of a handful of ATS platforms — Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee. And nearly all of them expose a public, documented JSON API for their postings.
Which means "scrape job postings" isn't really a scraping problem. It's a normalization problem: six different response shapes, board-slug discovery, HTML-encoded descriptions, and compensation data that's structured differently everywhere it exists at all.
Here's the DIY version, the one-call version, and one genuinely underrated thing hiding in this data.
The raw APIs
No key, no auth. These are live right now:
# Greenhouse
curl "https://boards-api.greenhouse.io/v1/boards/stripe/jobs"
# Lever
curl "https://api.lever.co/v0/postings/palantir?mode=json"
# Ashby
curl "https://api.ashbyhq.com/posting-api/job-board/openai"
Enter fullscreen mode Exit fullscreen mode
At the time of writing that's 518 open roles at Stripe, 280 at Palantir, and 727 at OpenAI — three calls, three completely different JSON shapes.
Greenhouse nests offices and departments as arrays of objects. Lever flattens everything into categories. Ashby puts the city in location.name and hides compensation behind a separate includeCompensation=true flag. Descriptions come back as escaped HTML on some, Markdown-ish on others. Multiply by six platforms and you've got a weekend project plus ongoing maintenance every time one of them changes.
The one-call version
Job Postings API auto-detects which ATS a company uses — from a bare slug or a full careers URL — and returns one normalized row per job. Here's a real, unedited record from a live run:
curl -X POST "https://api.apify.com/v2/acts/fetchbase~job-postings-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "companies": ["stripe", "gitlab", "https://jobs.ashbyhq.com/openai"] }'
Enter fullscreen mode Exit fullscreen mode
{
"company": "stripe",
"ats": "greenhouse",
"id": "7954688",
"title": "Account Executive, AI Sales (Grower)",
"department": "1654 Account Executives (AI)",
"location": "San Francisco, CA",
"remote": null,
"url": "https://stripe.com/jobs/search?gh_jid=7954688",
"publishedAt": "2026-07-21T18:51:19-04:00",
"salary": null,
"description": "## Who we are\n\n### About Stripe\n\nStripe is a financial infrastructure..."
}
Enter fullscreen mode Exit fullscreen mode
Note remote and salary are null there — and that's the honest part. Those fields are only as good as what the ATS publishes. Greenhouse boards frequently omit both. The actor normalizes the shape; it can't invent data the source doesn't expose.
Which brings us to the interesting bit.
The underrated part: some boards publish full comp
Ashby boards expose structured compensation, and plenty of companies leave it on. Of those 727 OpenAI roles, all 727 carry a published pay range — things like $257K – $335K • Offers Equity. 460 of them are flagged remote.
That is a real, public, structured compensation dataset that most people assume you have to buy from Levels.fyi or scrape out of rendered HTML. It's sitting behind a GET request.
Useful inputs while you're exploring:
| Input | Does |
|---|---|
companies |
Slugs or careers URLs — mix ATSes freely in one run |
remoteOnly |
Keep only roles the board flags remote |
titleFilter |
Substring match on title ("engineer") |
maxJobsPerCompany |
Cap big boards (default 1000) |
includeDescriptions |
Set false for a fast, light index |
You're billed per job returned, so filters cut cost as well as noise.
Things worth building with it
A "who's hiring in AI" snapshot. One run across several labs, compare volume and department mix:
A remote-jobs alert. remoteOnly + titleFilter: "engineer" across your target companies, on a schedule, diffed against yesterday's dataset → new postings to Slack:
Comp research. Pull a whole Ashby board and you get ranges attached to titles and locations:
Scrape OpenAI's openings — 727 live roles, all with pay ranges
Hiring as a market signal. Posting counts over time are a leading indicator — teams that are shipping are hiring, and teams in trouble quietly stop. Snapshot weekly and you've built a trends dataset nobody sells you.
Why the API route beats HTML scraping here
These are intended-use, documented endpoints. No bot walls, no proxy budget, no 3am breakage when a careers page gets redesigned. The tedious part — ATS detection, six-way shape merge, HTML→Markdown, comp parsing — is the part worth not rewriting yourself.
Pay per job returned, failed runs cost nothing, and Apify's free credits cover plenty of testing. The rest of the utility suite lives at apify.com/fetchbase.
Built this because job data shouldn't require scraping infrastructure. If you want another ATS supported or normalized salary output, say so in the comments or the actor's Issues tab.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.