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. 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: 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" 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 https://apify.com/fetchbase/job-postings-scraper 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 https://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.