cd /news/developer-tools/scrape-any-company-s-job-postings-gr… · home topics developer-tools article
[ARTICLE · art-67878] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Scrape any company's job postings — Greenhouse, Lever & Ashby, with one API call

A developer built a job postings scraper that normalizes data from six major ATS platforms — Greenhouse, Lever, Ashby, Workable, SmartRecruiters, and Recruitee — into a single API call. The tool auto-detects the ATS from a company slug or URL and returns one normalized row per job, including structured compensation data from Ashby boards. For example, all 727 OpenAI roles carry published pay ranges, and 460 are flagged remote.

read3 min views1 publishedJul 22, 2026

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.

No key, no auth. These are live right now:

curl "https://boards-api.greenhouse.io/v1/boards/stripe/jobs"
curl "https://api.lever.co/v0/postings/palantir?mode=json"
curl "https://api.ashbyhq.com/posting-api/job-board/openai"

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.

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"] }'
{
  "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..."
}

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.

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.

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.

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.

── more in #developer-tools 4 stories · sorted by recency
── more on @stripe 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/scrape-any-company-s…] indexed:0 read:3min 2026-07-22 ·